Merge pull request #3173 from bska/write-rft-seg-data
Enable SEG Type RFT File Output
This commit is contained in:
commit
5590b3c400
@ -74,6 +74,7 @@ namespace Opm {
|
||||
static WellSegments serializationTestObject();
|
||||
|
||||
std::size_t size() const;
|
||||
bool empty() const;
|
||||
double depthTopSegment() const;
|
||||
double lengthTopSegment() const;
|
||||
double volumeTopSegment() const;
|
||||
|
@ -73,6 +73,10 @@ namespace Opm {
|
||||
return m_segments.size();
|
||||
}
|
||||
|
||||
bool WellSegments::empty() const {
|
||||
return this->m_segments.empty();
|
||||
}
|
||||
|
||||
const Segment& WellSegments::topSegment() const {
|
||||
return this->m_segments[0];
|
||||
}
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -364,7 +365,60 @@ namespace {
|
||||
|
||||
// =======================================================================
|
||||
|
||||
class PLTFlowRate
|
||||
class PLTPhaseQuantity
|
||||
{
|
||||
public:
|
||||
explicit PLTPhaseQuantity(const std::size_t n = 0);
|
||||
virtual ~PLTPhaseQuantity() = default;
|
||||
|
||||
const std::vector<float>& oil() const { return this->oil_; }
|
||||
const std::vector<float>& gas() const { return this->gas_; }
|
||||
const std::vector<float>& water() const { return this->water_; }
|
||||
|
||||
protected:
|
||||
void addOil (const ::Opm::UnitSystem& usys, const float x);
|
||||
void addGas (const ::Opm::UnitSystem& usys, const float x);
|
||||
void addWater(const ::Opm::UnitSystem& usys, const float x);
|
||||
|
||||
private:
|
||||
std::vector<float> oil_{};
|
||||
std::vector<float> gas_{};
|
||||
std::vector<float> water_{};
|
||||
|
||||
[[nodiscard]] virtual ::Opm::UnitSystem::measure oilUnit() const = 0;
|
||||
[[nodiscard]] virtual ::Opm::UnitSystem::measure gasUnit() const = 0;
|
||||
[[nodiscard]] virtual ::Opm::UnitSystem::measure waterUnit() const = 0;
|
||||
};
|
||||
|
||||
void PLTPhaseQuantity::addOil(const ::Opm::UnitSystem& usys, const float x)
|
||||
{
|
||||
this->oil_.push_back(usys.from_si(this->oilUnit(), x));
|
||||
}
|
||||
|
||||
void PLTPhaseQuantity::addGas(const ::Opm::UnitSystem& usys, const float x)
|
||||
{
|
||||
this->gas_.push_back(usys.from_si(this->gasUnit(), x));
|
||||
}
|
||||
|
||||
void PLTPhaseQuantity::addWater(const ::Opm::UnitSystem& usys, const float x)
|
||||
{
|
||||
this->water_.push_back(usys.from_si(this->waterUnit(), x));
|
||||
}
|
||||
|
||||
PLTPhaseQuantity::PLTPhaseQuantity(const std::size_t n)
|
||||
{
|
||||
if (n == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->oil_.reserve(n);
|
||||
this->gas_.reserve(n);
|
||||
this->water_.reserve(n);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class PLTFlowRate : public PLTPhaseQuantity
|
||||
{
|
||||
public:
|
||||
explicit PLTFlowRate(const std::size_t nconn = 0);
|
||||
@ -372,40 +426,33 @@ namespace {
|
||||
void addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::data::Rates& rates);
|
||||
|
||||
const std::vector<float>& oil() const { return this->oil_; }
|
||||
const std::vector<float>& gas() const { return this->gas_; }
|
||||
const std::vector<float>& water() const { return this->water_; }
|
||||
|
||||
private:
|
||||
std::vector<float> oil_{};
|
||||
std::vector<float> gas_{};
|
||||
std::vector<float> water_{};
|
||||
[[nodiscard]] Opm::UnitSystem::measure oilUnit() const override
|
||||
{ return Opm::UnitSystem::measure::liquid_surface_rate; }
|
||||
|
||||
[[nodiscard]] Opm::UnitSystem::measure gasUnit() const override
|
||||
{ return Opm::UnitSystem::measure::gas_surface_rate; }
|
||||
|
||||
[[nodiscard]] Opm::UnitSystem::measure waterUnit() const override
|
||||
{ return Opm::UnitSystem::measure::liquid_surface_rate; }
|
||||
};
|
||||
|
||||
PLTFlowRate::PLTFlowRate(const std::size_t nconn)
|
||||
{
|
||||
if (nconn == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->oil_.reserve(nconn);
|
||||
this->gas_.reserve(nconn);
|
||||
this->water_.reserve(nconn);
|
||||
}
|
||||
: PLTPhaseQuantity{nconn}
|
||||
{}
|
||||
|
||||
void PLTFlowRate::addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::data::Rates& rates)
|
||||
{
|
||||
using M = Opm::UnitSystem::measure;
|
||||
using rt = Opm::data::Rates::opt;
|
||||
|
||||
// Note negative sign on call to rates.get() here. Flow reports
|
||||
// positive injection rates and negative production rates but we
|
||||
// need the opposite sign convention for this report.
|
||||
|
||||
this->oil_.push_back(usys.from_si(M::liquid_surface_rate, -rates.get(rt::oil, 0.0)));
|
||||
this->gas_.push_back(usys.from_si(M::gas_surface_rate, -rates.get(rt::gas, 0.0)));
|
||||
this->water_.push_back(usys.from_si(M::liquid_surface_rate, -rates.get(rt::wat, 0.0)));
|
||||
this->addOil (usys, -rates.get(rt::oil, 0.0));
|
||||
this->addGas (usys, -rates.get(rt::gas, 0.0));
|
||||
this->addWater(usys, -rates.get(rt::wat, 0.0));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@ -566,6 +613,8 @@ namespace {
|
||||
const std::function<int(int)>& binId,
|
||||
Cmp&& cmp);
|
||||
|
||||
int maxBinId() const { return this->maxId_; }
|
||||
|
||||
IndexRange bin(const int binId) const
|
||||
{
|
||||
this->verifyValid(binId);
|
||||
@ -679,6 +728,54 @@ namespace {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class OrderSegments
|
||||
{
|
||||
public:
|
||||
explicit OrderSegments(const ::Opm::WellSegments& wellSegs)
|
||||
: wellSegs_{ std::cref(wellSegs) }
|
||||
{}
|
||||
|
||||
bool operator()(const int i1, const int i2) const;
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const ::Opm::WellSegments> wellSegs_;
|
||||
};
|
||||
|
||||
// i1 < i2 if one of the following relations hold
|
||||
//
|
||||
// 1) i1's branch number is smaller than i2's branch number
|
||||
// 2) i1 and i2 are on the same branch, but i1 is i2's outlet segment
|
||||
// 3) Neither are each other's outlet segments, but i1 is closer to the
|
||||
// well head along the tubing.
|
||||
bool OrderSegments::operator()(const int i1, const int i2) const
|
||||
{
|
||||
const auto& s1 = this->wellSegs_.get()[i1];
|
||||
const auto& s2 = this->wellSegs_.get()[i2];
|
||||
|
||||
const auto b1 = s1.branchNumber();
|
||||
const auto b2 = s2.branchNumber();
|
||||
|
||||
if (b1 != b2) {
|
||||
// i1 not on same branch as i2. Order by branch number.
|
||||
return b1 < b2;
|
||||
}
|
||||
|
||||
if (s2.outletSegment() == s1.segmentNumber()) {
|
||||
// i1 is i2's outlet
|
||||
return true;
|
||||
}
|
||||
|
||||
if (s1.outletSegment() == s2.segmentNumber()) {
|
||||
// i2 is i1's outlet
|
||||
return false;
|
||||
}
|
||||
|
||||
// Neither is each other's outlet. Order by distance along tubing.
|
||||
return s1.totalLength() < s2.totalLength();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class PLTRecordMSW : public PLTRecord
|
||||
{
|
||||
public:
|
||||
@ -687,19 +784,6 @@ namespace {
|
||||
void write(::Opm::EclIO::OutputStream::RFT& rftFile) const override;
|
||||
|
||||
private:
|
||||
class OrderSegments
|
||||
{
|
||||
public:
|
||||
explicit OrderSegments(const ::Opm::WellSegments& wellSegs)
|
||||
: wellSegs_{ std::cref(wellSegs) }
|
||||
{}
|
||||
|
||||
bool operator()(const int i1, const int i2) const;
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const ::Opm::WellSegments> wellSegs_;
|
||||
};
|
||||
|
||||
class OrderSegConns
|
||||
{
|
||||
public:
|
||||
@ -880,41 +964,6 @@ namespace {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// i1 < i2 if one of the following relations hold
|
||||
//
|
||||
// 1) i1's branch number is smaller than i2's branch number
|
||||
// 2) i1 and i2 are on the same branch, but i1 is i2's outlet segment
|
||||
// 3) Neither are each other's outlet segments, but i1 is closer to the
|
||||
// well head along the tubing.
|
||||
bool PLTRecordMSW::OrderSegments::operator()(const int i1, const int i2) const
|
||||
{
|
||||
const auto& s1 = this->wellSegs_.get()[i1];
|
||||
const auto& s2 = this->wellSegs_.get()[i2];
|
||||
|
||||
const auto b1 = s1.branchNumber();
|
||||
const auto b2 = s2.branchNumber();
|
||||
|
||||
if (b1 != b2) {
|
||||
// i1 not on same branch as i2. Order by branch number.
|
||||
return b1 < b2;
|
||||
}
|
||||
|
||||
if (s2.outletSegment() == s1.segmentNumber()) {
|
||||
// i1 is i2's outlet
|
||||
return true;
|
||||
}
|
||||
|
||||
if (s1.outletSegment() == s2.segmentNumber()) {
|
||||
// i2 is i1's outlet
|
||||
return false;
|
||||
}
|
||||
|
||||
// Neither is each other's outlet. Order by distance along tubing.
|
||||
return s1.totalLength() < s2.totalLength();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// i1 < i2 if one of the following relations hold
|
||||
//
|
||||
// 1) i1's branch number is smaller than i2's branch number
|
||||
@ -964,13 +1013,320 @@ namespace {
|
||||
return this->wellConns_.get()[connIdx].perf_range()->second;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class SegmentRecord
|
||||
{
|
||||
public:
|
||||
explicit SegmentRecord(const std::size_t nseg = 0);
|
||||
|
||||
void collectRecordData(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
const ::Opm::data::Well& wellSol);
|
||||
|
||||
std::size_t nSeg() const { return this->neighbour_id_.size(); }
|
||||
|
||||
void write(::Opm::EclIO::OutputStream::RFT& rftFile) const;
|
||||
|
||||
private:
|
||||
PLTFlowRate rate_{};
|
||||
|
||||
std::vector<int> neighbour_id_{};
|
||||
std::vector<int> branch_id_{};
|
||||
|
||||
std::vector<int> branch_start_segment_{};
|
||||
std::vector<int> branch_end_segment_{};
|
||||
|
||||
std::vector<float> diameter_{};
|
||||
std::vector<float> depth_{};
|
||||
std::vector<float> start_length_{};
|
||||
std::vector<float> end_length_{};
|
||||
std::vector<float> x_coord_{};
|
||||
std::vector<float> y_coord_{};
|
||||
std::vector<float> pressure_{};
|
||||
std::vector<float> strength_{};
|
||||
std::vector<float> icd_setting_{};
|
||||
|
||||
void defineBranches(const ::Opm::WellSegments& segments);
|
||||
|
||||
void addSegment(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::WellSegments& segments,
|
||||
const ::Opm::Segment& segment,
|
||||
const ::Opm::data::Segment& segSol);
|
||||
|
||||
void recordPhysicalLocation(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::WellSegments& segments,
|
||||
const ::Opm::Segment& segment);
|
||||
|
||||
void recordSegmentConnectivity(const ::Opm::Segment& segment);
|
||||
|
||||
void recordSegmentProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
|
||||
void recordDynamicState(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment,
|
||||
const ::Opm::data::Segment& segSol);
|
||||
|
||||
void recordAutoICDTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
void recordRegularTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
void recordSpiralICDTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
void recordValveTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
};
|
||||
|
||||
SegmentRecord::SegmentRecord(const std::size_t nseg)
|
||||
: rate_{ nseg }
|
||||
{
|
||||
if (nseg == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->neighbour_id_.reserve(nseg);
|
||||
this->branch_id_.reserve(nseg);
|
||||
|
||||
this->diameter_.reserve(nseg);
|
||||
this->depth_.reserve(nseg);
|
||||
this->start_length_.reserve(nseg);
|
||||
this->end_length_.reserve(nseg);
|
||||
this->x_coord_.reserve(nseg);
|
||||
this->y_coord_.reserve(nseg);
|
||||
this->pressure_.reserve(nseg);
|
||||
this->strength_.reserve(nseg);
|
||||
this->icd_setting_.reserve(nseg);
|
||||
}
|
||||
|
||||
void SegmentRecord::write(::Opm::EclIO::OutputStream::RFT& rftFile) const
|
||||
{
|
||||
rftFile.write("SEGDIAM", this->diameter_);
|
||||
rftFile.write("SEGDEPTH", this->depth_);
|
||||
rftFile.write("SEGLENST", this->start_length_);
|
||||
rftFile.write("SEGLENEN", this->end_length_);
|
||||
|
||||
rftFile.write("SEGXCORD", this->x_coord_);
|
||||
rftFile.write("SEGYCORD", this->y_coord_);
|
||||
rftFile.write("SEGPRES", this->pressure_);
|
||||
|
||||
rftFile.write("SEGORAT", this->rate_.oil());
|
||||
rftFile.write("SEGWRAT", this->rate_.water());
|
||||
rftFile.write("SEGGRAT", this->rate_.gas());
|
||||
|
||||
rftFile.write("SEGSSTR", this->strength_);
|
||||
rftFile.write("SEGSFOPN", this->icd_setting_);
|
||||
rftFile.write("SEGBRNO", this->branch_id_);
|
||||
rftFile.write("SEGNXT", this->neighbour_id_);
|
||||
|
||||
rftFile.write("BRNST", this->branch_start_segment_);
|
||||
rftFile.write("BRNEN", this->branch_end_segment_);
|
||||
}
|
||||
|
||||
void SegmentRecord::collectRecordData(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
const ::Opm::data::Well& wellSol)
|
||||
{
|
||||
const auto& segments = well.getSegments();
|
||||
const auto& xseg = wellSol.segments;
|
||||
|
||||
for (const auto& segment : segments) {
|
||||
auto segSolPos = xseg.find(segment.segmentNumber());
|
||||
if (segSolPos == xseg.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->addSegment(usys, segments, segment, segSolPos->second);
|
||||
}
|
||||
|
||||
if (this->nSeg() > std::size_t{0}) {
|
||||
this->defineBranches(segments);
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentRecord::defineBranches(const ::Opm::WellSegments& wellSegs)
|
||||
{
|
||||
auto branchSegments = CSRIndexRelation {};
|
||||
const auto minBranchID = 1;
|
||||
|
||||
branchSegments.build(wellSegs.size(), minBranchID,
|
||||
[&wellSegs](const int ix) { return wellSegs[ix].branchNumber(); },
|
||||
OrderSegments { wellSegs });
|
||||
|
||||
const auto maxBranchID = branchSegments.maxBinId();
|
||||
this->branch_start_segment_.assign(maxBranchID, 0);
|
||||
this->branch_end_segment_ .assign(maxBranchID, 0);
|
||||
|
||||
auto segNum = [&wellSegs](const int segIx) {
|
||||
return wellSegs[segIx].segmentNumber();
|
||||
};
|
||||
|
||||
for (auto branch = minBranchID; branch <= maxBranchID; ++branch) {
|
||||
auto [begin, end] = branchSegments.bin(branch);
|
||||
if (end == begin) {
|
||||
// Empty branch (no segments). Unexpected.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto branchIx = branch - minBranchID;
|
||||
this->branch_start_segment_[branchIx] = segNum(*begin);
|
||||
this->branch_end_segment_ [branchIx] = segNum(*(end - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentRecord::addSegment(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::WellSegments& segments,
|
||||
const ::Opm::Segment& segment,
|
||||
const Opm::data::Segment& segSol)
|
||||
{
|
||||
this->recordPhysicalLocation(usys, segments, segment);
|
||||
this->recordSegmentConnectivity(segment);
|
||||
this->recordSegmentProperties(usys, segment);
|
||||
this->recordDynamicState(usys, segment, segSol);
|
||||
}
|
||||
|
||||
void SegmentRecord::recordPhysicalLocation(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::WellSegments& segments,
|
||||
const ::Opm::Segment& segment)
|
||||
{
|
||||
auto cvrt = [&usys](const double x) -> float
|
||||
{
|
||||
return usys.from_si(::Opm::UnitSystem::measure::length, x);
|
||||
};
|
||||
|
||||
{
|
||||
const auto diam = std::max(0.0, segment.internalDiameter());
|
||||
this->diameter_.push_back(cvrt(diam));
|
||||
}
|
||||
|
||||
this->depth_.push_back(cvrt(segment.depth()));
|
||||
|
||||
{
|
||||
const auto outletNum = segment.outletSegment();
|
||||
const auto start = (outletNum <= 0)
|
||||
? 0.0 // 'segment' is top segment
|
||||
: segments.getFromSegmentNumber(outletNum).totalLength();
|
||||
|
||||
this->start_length_.push_back(cvrt(start));
|
||||
}
|
||||
|
||||
this->end_length_.push_back(cvrt(segment.totalLength()));
|
||||
this->x_coord_.push_back(cvrt(segment.node_X()));
|
||||
this->y_coord_.push_back(cvrt(segment.node_Y()));
|
||||
}
|
||||
|
||||
void SegmentRecord::recordSegmentConnectivity(const ::Opm::Segment& segment)
|
||||
{
|
||||
this->neighbour_id_.push_back(segment.outletSegment());
|
||||
this->branch_id_ .push_back(segment.branchNumber());
|
||||
}
|
||||
|
||||
void SegmentRecord::recordSegmentProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment)
|
||||
{
|
||||
using TypeProperties = void(SegmentRecord::*)
|
||||
(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment);
|
||||
|
||||
static const auto handlers = std::array<TypeProperties, 4> {
|
||||
&SegmentRecord::recordRegularTypeProperties,
|
||||
&SegmentRecord::recordSpiralICDTypeProperties,
|
||||
&SegmentRecord::recordAutoICDTypeProperties,
|
||||
&SegmentRecord::recordValveTypeProperties,
|
||||
};
|
||||
|
||||
const auto ix = static_cast<std::size_t>(segment.segmentType());
|
||||
if (ix < handlers.size()) {
|
||||
(this->*handlers[ix])(usys, segment);
|
||||
}
|
||||
else {
|
||||
// Unknown segment type. Treat as "regular".
|
||||
this->recordRegularTypeProperties(usys, segment);
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentRecord::recordDynamicState(const ::Opm::UnitSystem& usys,
|
||||
[[maybe_unused]] const ::Opm::Segment& segment,
|
||||
const ::Opm::data::Segment& segSol)
|
||||
{
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
using SegPress = ::Opm::data::SegmentPressures::Value;
|
||||
|
||||
this->pressure_.push_back(usys.from_si(M::pressure, segSol.pressures[SegPress::Pressure]));
|
||||
this->rate_.addConnection(usys, segSol.rates);
|
||||
}
|
||||
|
||||
void SegmentRecord::recordAutoICDTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment)
|
||||
{
|
||||
this->strength_.push_back(usys.from_si(::Opm::UnitSystem::measure::aicd_strength,
|
||||
segment.autoICD().strength()));
|
||||
this->icd_setting_.push_back(1.0f);
|
||||
}
|
||||
|
||||
void SegmentRecord::recordRegularTypeProperties([[maybe_unused]] const ::Opm::UnitSystem& usys,
|
||||
[[maybe_unused]] const ::Opm::Segment& segment)
|
||||
{
|
||||
this->strength_.push_back(0.0f);
|
||||
this->icd_setting_.push_back(1.0f);
|
||||
}
|
||||
|
||||
void SegmentRecord::recordSpiralICDTypeProperties(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment)
|
||||
{
|
||||
this->strength_.push_back(usys.from_si(::Opm::UnitSystem::measure::icd_strength,
|
||||
segment.spiralICD().strength()));
|
||||
this->icd_setting_.push_back(1.0f);
|
||||
}
|
||||
|
||||
double valveMaximumCrossSectionalArea(const ::Opm::Segment& segment)
|
||||
{
|
||||
assert ((segment.segmentNumber() > 1) && segment.isValve());
|
||||
|
||||
// Data sources in order of preference:
|
||||
//
|
||||
// 1. WSEGVALV(10) (= valve.conMaxCrossArea()), if set
|
||||
// 2. WSEGVALV( 8) (= valve.pipeCrossArea()), if set
|
||||
// 3. WELSEGS ( 9) (= segment.crossArea())
|
||||
|
||||
const auto& valve = segment.valve();
|
||||
if (const auto ac_max = valve.conMaxCrossArea(); ac_max > 0.0) {
|
||||
return ac_max;
|
||||
}
|
||||
|
||||
if (const auto ac_max = valve.pipeCrossArea(); ac_max > 0.0) {
|
||||
return ac_max;
|
||||
}
|
||||
|
||||
return segment.crossArea();
|
||||
}
|
||||
|
||||
// ICD setting ("SEGSFOPN") for valves is cross-sectional area in valve
|
||||
// constriction (Ac) relative to maximum cross-sectional area in value
|
||||
// constriction (Ac_max).
|
||||
double valveICDSetting(const ::Opm::Segment& segment)
|
||||
{
|
||||
assert ((segment.segmentNumber() > 1) && segment.isValve());
|
||||
|
||||
const auto Ac = segment.valve().conCrossArea();
|
||||
const auto Ac_max = valveMaximumCrossSectionalArea(segment);
|
||||
|
||||
return Ac / Ac_max;
|
||||
}
|
||||
|
||||
void SegmentRecord::recordValveTypeProperties([[maybe_unused]] const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Segment& segment)
|
||||
{
|
||||
this->strength_.push_back(0.0f);
|
||||
this->icd_setting_.push_back(valveICDSetting(segment));
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
|
||||
class WellRFTOutputData
|
||||
{
|
||||
public:
|
||||
enum class DataTypes {
|
||||
RFT, PLT,
|
||||
RFT, PLT, SEG,
|
||||
};
|
||||
|
||||
explicit WellRFTOutputData(const std::vector<DataTypes>& types,
|
||||
@ -1008,6 +1364,7 @@ namespace {
|
||||
std::unique_ptr<WellConnectionRecord> wconns_{};
|
||||
std::unique_ptr<RFTRecord> rft_{};
|
||||
std::unique_ptr<PLTRecord> plt_{};
|
||||
std::unique_ptr<SegmentRecord> seg_{};
|
||||
|
||||
std::vector<DataHandler> dataHandlers_{};
|
||||
std::vector<RecordWriter> recordWriters_{};
|
||||
@ -1017,10 +1374,12 @@ namespace {
|
||||
void initialiseConnHandlers();
|
||||
void initialiseRFTHandlers();
|
||||
void initialisePLTHandlers();
|
||||
void initialiseSEGHandlers();
|
||||
|
||||
bool haveOutputData() const;
|
||||
bool haveRFTData() const;
|
||||
bool havePLTData() const;
|
||||
bool haveSEGData() const;
|
||||
|
||||
void writeHeader(::Opm::EclIO::OutputStream::RFT& rftFile) const;
|
||||
|
||||
@ -1056,7 +1415,8 @@ namespace {
|
||||
bool WellRFTOutputData::haveOutputData() const
|
||||
{
|
||||
return this->haveRFTData()
|
||||
|| this->havePLTData();
|
||||
|| this->havePLTData()
|
||||
|| this->haveSEGData();
|
||||
}
|
||||
|
||||
void WellRFTOutputData::addDynamicData(const Opm::data::Well& wellSol)
|
||||
@ -1150,6 +1510,30 @@ namespace {
|
||||
});
|
||||
}
|
||||
|
||||
void WellRFTOutputData::initialiseSEGHandlers()
|
||||
{
|
||||
const auto& well = this->well_.get();
|
||||
|
||||
if (!well.isMultiSegment() || well.getSegments().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->seg_ = std::make_unique<SegmentRecord>
|
||||
(well.getSegments().size());
|
||||
|
||||
this->dataHandlers_.emplace_back(
|
||||
[this](const Opm::data::Well& wellSol)
|
||||
{
|
||||
this->seg_->collectRecordData(this->usys_, this->well_, wellSol);
|
||||
});
|
||||
|
||||
this->recordWriters_.emplace_back(
|
||||
[this](::Opm::EclIO::OutputStream::RFT& rftFile)
|
||||
{
|
||||
this->seg_->write(rftFile);
|
||||
});
|
||||
}
|
||||
|
||||
bool WellRFTOutputData::haveRFTData() const
|
||||
{
|
||||
return (this->rft_ != nullptr)
|
||||
@ -1162,6 +1546,12 @@ namespace {
|
||||
&& (this->plt_->nConn() > std::size_t{0});
|
||||
}
|
||||
|
||||
bool WellRFTOutputData::haveSEGData() const
|
||||
{
|
||||
return (this->seg_ != nullptr)
|
||||
&& (this->seg_->nSeg() > std::size_t{0});
|
||||
}
|
||||
|
||||
void WellRFTOutputData::writeHeader(::Opm::EclIO::OutputStream::RFT& rftFile) const
|
||||
{
|
||||
{
|
||||
@ -1229,8 +1619,9 @@ namespace {
|
||||
std::string WellRFTOutputData::dataTypeString() const
|
||||
{
|
||||
auto tstring = std::string{};
|
||||
if (this->haveRFTData()) { tstring += 'R';}
|
||||
if (this->havePLTData()) { tstring += 'P';}
|
||||
if (this->haveRFTData()) { tstring += 'R'; }
|
||||
if (this->havePLTData()) { tstring += 'P'; }
|
||||
if (this->haveSEGData()) { tstring += 'S'; }
|
||||
|
||||
return tstring;
|
||||
}
|
||||
@ -1246,6 +1637,7 @@ namespace {
|
||||
WellRFTOutputData::creators_{
|
||||
{ WellRFTOutputData::DataTypes::RFT, &WellRFTOutputData::initialiseRFTHandlers },
|
||||
{ WellRFTOutputData::DataTypes::PLT, &WellRFTOutputData::initialisePLTHandlers },
|
||||
{ WellRFTOutputData::DataTypes::SEG, &WellRFTOutputData::initialiseSEGHandlers },
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
@ -1266,6 +1658,10 @@ namespace {
|
||||
rftTypes.push_back(WellRFTOutputData::DataTypes::PLT);
|
||||
}
|
||||
|
||||
if (rft_config.segment(well_name)) {
|
||||
rftTypes.push_back(WellRFTOutputData::DataTypes::SEG);
|
||||
}
|
||||
|
||||
return rftTypes;
|
||||
}
|
||||
}
|
||||
|
1257
tests/test_RFT.cpp
1257
tests/test_RFT.cpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user