Add Basic PLT Information to RFT Output File
We support both standard and multisegmented wells, but do not output every known PLT array. Notably missing are - WELLPLT - Brine flow rate (CONSRAT) - Phase flow rates through tubing (CONxTUB) Computing CONNXT for multisegmented wells is somewhat involved, and requires sorting the connections according to branch number, segments, and tubing lengths. We use an ancillary structure, an array of indices into a WellConnections object, along with a custom predicate to perform this sorting. As an implementation detail, we handle PLT data for multisegmented wells as an extension of the PLT data for regular/standard wells. This extension is realised through dynamic polymorphism. Add unit tests to cover PLT data for both well types.
This commit is contained in:
parent
078b7b2e28
commit
9bb733b69b
@ -32,23 +32,32 @@
|
||||
#include <opm/output/eclipse/InteHEAD.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
#include <opm/input/eclipse/Schedule/RFTConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Schedule.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/Segment.hpp>
|
||||
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace {
|
||||
enum etcIx : std::vector<Opm::EclIO::PaddedOutputString<8>>::size_type
|
||||
{
|
||||
@ -170,9 +179,12 @@ namespace {
|
||||
return xc.index == cellIndex;
|
||||
});
|
||||
|
||||
return (pos != xcon.end())
|
||||
? std::optional{pos} // C++17 class template argument deduction
|
||||
: std::nullopt;
|
||||
if (pos == xcon.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// C++17 class template argument deduction.
|
||||
return std::optional{pos};
|
||||
}
|
||||
|
||||
template <typename ConnectionIsActive, typename ConnOp>
|
||||
@ -348,7 +360,608 @@ namespace {
|
||||
|
||||
this->swat_.push_back(xcon.cell_saturation_water);
|
||||
this->sgas_.push_back(xcon.cell_saturation_gas);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
|
||||
class PLTFlowRate
|
||||
{
|
||||
public:
|
||||
explicit PLTFlowRate(const std::size_t nconn = 0);
|
||||
|
||||
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_{};
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class PLTRecord
|
||||
{
|
||||
public:
|
||||
explicit PLTRecord(const std::size_t nconn = 0);
|
||||
virtual ~PLTRecord() = default;
|
||||
|
||||
void collectRecordData(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::EclipseGrid& grid,
|
||||
const ::Opm::Well& well,
|
||||
const ::Opm::data::Well& wellSol);
|
||||
|
||||
std::size_t nConn() const { return this->depth_.size(); }
|
||||
|
||||
virtual void write(::Opm::EclIO::OutputStream::RFT& rftFile) const;
|
||||
|
||||
protected:
|
||||
using ConnPos = ::Opm::WellConnections::const_iterator;
|
||||
|
||||
virtual void prepareConnections(const ::Opm::Well& well);
|
||||
|
||||
virtual void addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
ConnPos connPos,
|
||||
const ::Opm::data::Connection& xcon);
|
||||
|
||||
void assignNextNeighbourID(const int id);
|
||||
|
||||
private:
|
||||
PLTFlowRate flow_{};
|
||||
|
||||
std::vector<int> neighbour_id_{};
|
||||
|
||||
std::vector<float> depth_{};
|
||||
std::vector<float> pressure_{};
|
||||
std::vector<float> trans_{};
|
||||
std::vector<float> kh_{};
|
||||
|
||||
void assignNextNeighbourID(ConnPos connPos,
|
||||
const ::Opm::WellConnections& wellConns);
|
||||
};
|
||||
|
||||
PLTRecord::PLTRecord(const std::size_t nconn)
|
||||
: flow_{nconn}
|
||||
{
|
||||
if (nconn == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->neighbour_id_.reserve(nconn);
|
||||
this->depth_.reserve(nconn);
|
||||
this->pressure_.reserve(nconn);
|
||||
this->trans_.reserve(nconn);
|
||||
this->kh_.reserve(nconn);
|
||||
}
|
||||
|
||||
void PLTRecord::collectRecordData(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::EclipseGrid& grid,
|
||||
const ::Opm::Well& well,
|
||||
const ::Opm::data::Well& wellSol)
|
||||
{
|
||||
this->prepareConnections(well);
|
||||
|
||||
const auto& xcon = wellSol.connections;
|
||||
connectionLoop(well.getConnections(), grid,
|
||||
[this, &usys, &well, &xcon](ConnPos connPos)
|
||||
{
|
||||
const auto xconPos =
|
||||
findConnResults(connPos->global_index(), xcon);
|
||||
|
||||
if (! xconPos.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->addConnection(usys, well, connPos, *xconPos.value());
|
||||
});
|
||||
}
|
||||
|
||||
void PLTRecord::write(::Opm::EclIO::OutputStream::RFT& rftFile) const
|
||||
{
|
||||
rftFile.write("CONDEPTH", this->depth_);
|
||||
rftFile.write("CONPRES" , this->pressure_);
|
||||
|
||||
rftFile.write("CONORAT", this->flow_.oil());
|
||||
rftFile.write("CONWRAT", this->flow_.water());
|
||||
rftFile.write("CONGRAT", this->flow_.gas());
|
||||
|
||||
rftFile.write("CONFAC", this->trans_);
|
||||
rftFile.write("CONKH" , this->kh_);
|
||||
rftFile.write("CONNXT", this->neighbour_id_);
|
||||
}
|
||||
|
||||
void PLTRecord::prepareConnections([[maybe_unused]] const ::Opm::Well& well)
|
||||
{}
|
||||
|
||||
void PLTRecord::addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
ConnPos connPos,
|
||||
const ::Opm::data::Connection& xcon)
|
||||
{
|
||||
using M = ::Opm::UnitSystem::measure;
|
||||
auto cvrt = [&usys](const M meas, const double x) -> float
|
||||
{
|
||||
return usys.from_si(meas, x);
|
||||
};
|
||||
|
||||
// Allocate neighbour ID element
|
||||
this->neighbour_id_.push_back(0);
|
||||
|
||||
// Infer neighbour connection in direction of well head.
|
||||
this->assignNextNeighbourID(connPos, well.getConnections());
|
||||
|
||||
this->depth_.push_back(cvrt(M::length, connPos->depth()));
|
||||
this->pressure_.push_back(cvrt(M::pressure, xcon.pressure));
|
||||
this->trans_.push_back(cvrt(M::transmissibility, xcon.trans_factor));
|
||||
this->kh_.push_back(cvrt(M::effective_Kh, connPos->Kh()));
|
||||
|
||||
this->flow_.addConnection(usys, xcon.rates);
|
||||
}
|
||||
|
||||
void PLTRecord::assignNextNeighbourID(ConnPos connPos,
|
||||
const ::Opm::WellConnections& wellConns)
|
||||
{
|
||||
auto begin = wellConns.begin();
|
||||
|
||||
if (connPos == begin) {
|
||||
// This connection is closest to the well head and there is no
|
||||
// neighbour.
|
||||
this->assignNextNeighbourID(0);
|
||||
}
|
||||
else {
|
||||
const auto connIdx = std::distance(begin, connPos);
|
||||
std::advance(begin, connIdx - 1);
|
||||
|
||||
this->assignNextNeighbourID(static_cast<int>(begin->sort_value()) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PLTRecord::assignNextNeighbourID(const int id)
|
||||
{
|
||||
this->neighbour_id_.back() = id;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class CSRIndexRelation
|
||||
{
|
||||
public:
|
||||
using IndexRange = std::pair<std::vector<int>::const_iterator,
|
||||
std::vector<int>::const_iterator>;
|
||||
|
||||
template <typename Cmp>
|
||||
void build(const std::size_t size,
|
||||
const int minId,
|
||||
const std::function<int(int)>& binId,
|
||||
Cmp&& cmp);
|
||||
|
||||
IndexRange bin(const int binId) const
|
||||
{
|
||||
this->verifyValid(binId);
|
||||
|
||||
return { this->start(binId), this->start(binId + 1) };
|
||||
}
|
||||
|
||||
bool empty(const int binId) const
|
||||
{
|
||||
this->verifyValid(binId);
|
||||
|
||||
return this->start(binId) == this->start(binId + 1);
|
||||
}
|
||||
|
||||
std::optional<int> last(const int binId) const
|
||||
{
|
||||
this->verifyValid(binId);
|
||||
|
||||
if (this->empty(binId)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto end = this->start(binId + 1);
|
||||
return *--end;
|
||||
}
|
||||
|
||||
private:
|
||||
int minId_{std::numeric_limits<int>::max()};
|
||||
int maxId_{std::numeric_limits<int>::min()};
|
||||
|
||||
std::vector<std::vector<int>::size_type> pos_{};
|
||||
std::vector<int> ix_{};
|
||||
|
||||
std::vector<int>::const_iterator start(const int binId) const
|
||||
{
|
||||
return this->ix_.begin() + this->pos_[binId - this->minId_];
|
||||
}
|
||||
|
||||
bool valid(const int binId) const
|
||||
{
|
||||
return (binId >= this->minId_)
|
||||
&& (binId <= this->maxId_);
|
||||
}
|
||||
|
||||
void verifyValid(const int binId) const
|
||||
{
|
||||
if (this->valid(binId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::invalid_argument {
|
||||
fmt::format("Bin ID {} outside valid range {}..{}",
|
||||
binId, this->minId_, this->maxId_)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Cmp>
|
||||
void CSRIndexRelation::build(const std::size_t size,
|
||||
const int minId,
|
||||
const std::function<int(int)>& binId,
|
||||
Cmp&& cmp)
|
||||
{
|
||||
if (size == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->ix_.resize(size);
|
||||
std::iota(this->ix_.begin(), this->ix_.end(), 0);
|
||||
std::sort(this->ix_.begin(), this->ix_.end(), std::forward<Cmp>(cmp));
|
||||
|
||||
// Sort must respect binId(i1) <= binId(i2)
|
||||
auto inconsistentId =
|
||||
std::adjacent_find(this->ix_.begin(),
|
||||
this->ix_.end(),
|
||||
[&binId](const int i1, const int i2)
|
||||
{
|
||||
return binId(i1) > binId(i2);
|
||||
});
|
||||
|
||||
if (inconsistentId != this->ix_.end()) {
|
||||
throw std::invalid_argument {
|
||||
"Comparison operator does not honour bin consistency requirement"
|
||||
};
|
||||
}
|
||||
|
||||
const auto binIdBounds =
|
||||
std::minmax_element(this->ix_.begin(), this->ix_.end(),
|
||||
[&binId](const int i1, const int i2)
|
||||
{ return binId(i1) < binId(i2); });
|
||||
|
||||
if (binIdBounds.first != this->ix_.end()) {
|
||||
this->minId_ = std::min(binId(*binIdBounds.first), minId);
|
||||
this->maxId_ = binId(*binIdBounds.second);
|
||||
}
|
||||
|
||||
if (this->minId_ < minId) {
|
||||
// Not particularly likely, but nevertheless possible.
|
||||
throw std::invalid_argument {
|
||||
"Bin ID function does not honour minimum ID requirement"
|
||||
};
|
||||
}
|
||||
|
||||
this->pos_.resize(this->maxId_ - this->minId_ + 1 + 1);
|
||||
for (const auto& ix : this->ix_) {
|
||||
this->pos_[binId(ix) + 1 - this->minId_] += 1;
|
||||
}
|
||||
|
||||
std::partial_sum(this->pos_.begin(), this->pos_.end(), this->pos_.begin());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class PLTRecordMSW : public PLTRecord
|
||||
{
|
||||
public:
|
||||
explicit PLTRecordMSW(const std::size_t nconn = 0);
|
||||
|
||||
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:
|
||||
explicit OrderSegConns(const ::Opm::WellSegments& wellSegs,
|
||||
const ::Opm::WellConnections& wellConns)
|
||||
: wellSegs_ { std::cref(wellSegs) }
|
||||
, wellConns_ { std::cref(wellConns) }
|
||||
, segOrderedBefore_{ wellSegs }
|
||||
{}
|
||||
|
||||
bool operator()(const int i1, const int i2) const;
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const ::Opm::WellSegments> wellSegs_;
|
||||
std::reference_wrapper<const ::Opm::WellConnections> wellConns_;
|
||||
OrderSegments segOrderedBefore_;
|
||||
|
||||
int segIdx(const int connIdx) const;
|
||||
int segNum(const int connIdx) const;
|
||||
int brnNum(const int segIx) const;
|
||||
double connDistance(const int connIdx) const;
|
||||
};
|
||||
|
||||
std::vector<int> segment_id_{};
|
||||
std::vector<int> branch_id_{};
|
||||
|
||||
std::vector<float> start_length_{};
|
||||
std::vector<float> end_length_{};
|
||||
|
||||
CSRIndexRelation segmentConns_{};
|
||||
|
||||
void prepareConnections(const ::Opm::Well& well) override;
|
||||
|
||||
void addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
ConnPos connPos,
|
||||
const ::Opm::data::Connection& xcon) override;
|
||||
|
||||
void initialiseSegmentConns(const ::Opm::WellSegments& wellSegs,
|
||||
const ::Opm::WellConnections& wellConns);
|
||||
|
||||
int nextNeighbourConnection(ConnPos connPos,
|
||||
const ::Opm::WellSegments& wellSegs,
|
||||
const ::Opm::WellConnections& wellConns) const;
|
||||
};
|
||||
|
||||
PLTRecordMSW::PLTRecordMSW(const std::size_t nconn)
|
||||
: PLTRecord{ nconn }
|
||||
{
|
||||
if (nconn == std::size_t{0}) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->segment_id_.reserve(nconn);
|
||||
this->branch_id_.reserve(nconn);
|
||||
this->start_length_.reserve(nconn);
|
||||
this->end_length_.reserve(nconn);
|
||||
}
|
||||
|
||||
void PLTRecordMSW::write(::Opm::EclIO::OutputStream::RFT& rftFile) const
|
||||
{
|
||||
PLTRecord::write(rftFile);
|
||||
|
||||
rftFile.write("CONLENST", this->start_length_);
|
||||
rftFile.write("CONLENEN", this->end_length_);
|
||||
rftFile.write("CONSEGNO", this->segment_id_);
|
||||
rftFile.write("CONBRNO", this->branch_id_);
|
||||
}
|
||||
|
||||
void PLTRecordMSW::prepareConnections(const ::Opm::Well& well)
|
||||
{
|
||||
PLTRecord::prepareConnections(well);
|
||||
|
||||
this->initialiseSegmentConns(well.getSegments(), well.getConnections());
|
||||
}
|
||||
|
||||
void PLTRecordMSW::addConnection(const ::Opm::UnitSystem& usys,
|
||||
const ::Opm::Well& well,
|
||||
ConnPos connPos,
|
||||
const ::Opm::data::Connection& xcon)
|
||||
{
|
||||
PLTRecord::addConnection(usys, well, connPos, xcon);
|
||||
|
||||
if (! connPos->attachedToSegment()) {
|
||||
this->segment_id_.push_back(0);
|
||||
this->branch_id_.push_back(0);
|
||||
this->start_length_.push_back(0.0f);
|
||||
this->end_length_.push_back(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const auto id = this->nextNeighbourConnection
|
||||
(connPos, well.getSegments(), well.getConnections());
|
||||
|
||||
this->assignNextNeighbourID(id);
|
||||
}
|
||||
|
||||
this->segment_id_.push_back(connPos->segment());
|
||||
|
||||
{
|
||||
const auto branch = well.getSegments()
|
||||
.getFromSegmentNumber(this->segment_id_.back())
|
||||
.branchNumber();
|
||||
|
||||
this->branch_id_.push_back(branch);
|
||||
}
|
||||
|
||||
auto segLength = [&usys](const double len) -> float
|
||||
{
|
||||
return usys.from_si(Opm::UnitSystem::measure::length, len);
|
||||
};
|
||||
|
||||
const auto& [start_md, end_md] = connPos->perf_range().value();
|
||||
this->start_length_.push_back(segLength(start_md));
|
||||
this->end_length_.push_back(segLength(end_md));
|
||||
}
|
||||
|
||||
void PLTRecordMSW::initialiseSegmentConns(const ::Opm::WellSegments& wellSegs,
|
||||
const ::Opm::WellConnections& wellConns)
|
||||
{
|
||||
const auto minSegNum = 1;
|
||||
|
||||
this->segmentConns_.build(wellConns.size(), minSegNum,
|
||||
[&wellConns](const int ix) { return wellConns[ix].segment(); },
|
||||
OrderSegConns { wellSegs, wellConns });
|
||||
}
|
||||
|
||||
int PLTRecordMSW::nextNeighbourConnection(ConnPos connPos,
|
||||
const ::Opm::WellSegments& wellSegs,
|
||||
const ::Opm::WellConnections& wellConns) const
|
||||
{
|
||||
const auto connIx = std::distance(wellConns.begin(), connPos);
|
||||
const auto segNum = connPos->segment();
|
||||
const auto topSeg = 1;
|
||||
|
||||
auto connRng = this->segmentConns_.bin(segNum);
|
||||
if (connRng.first == connRng.second) {
|
||||
throw std::runtime_error {
|
||||
"Internal error in segment allocation"
|
||||
};
|
||||
}
|
||||
|
||||
auto getConnectionId = [&wellConns](const std::size_t ix)
|
||||
{
|
||||
return wellConns[ix].sort_value() + 1;
|
||||
};
|
||||
|
||||
if (*connRng.first != connIx) {
|
||||
// Not first connection in `segNum`. Typical case. Neighbour
|
||||
// is next connection closer to the outlet.
|
||||
auto i = std::find(connRng.first, connRng.second, connIx);
|
||||
assert (i != connRng.second);
|
||||
return getConnectionId(*(i - 1));
|
||||
}
|
||||
|
||||
if (segNum == topSeg) {
|
||||
// We're first connection in top segment. No other connection
|
||||
// neighbour exists in the direction of the well head.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We're first connection in `segNum` so search upwards towards top
|
||||
// segment, through outletSegment(), for first non-empty segment and
|
||||
// pick the *last* connection in that segment.
|
||||
auto out = wellSegs.getFromSegmentNumber(segNum).outletSegment();
|
||||
while ((out != topSeg) && this->segmentConns_.empty(out)) {
|
||||
out = wellSegs.getFromSegmentNumber(out).outletSegment();
|
||||
}
|
||||
|
||||
if (this->segmentConns_.empty(out)) {
|
||||
// No other connections closer to well head exist.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getConnectionId(this->segmentConns_.last(out).value());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// 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
|
||||
// 2) i1's segment is ordered before i2's segment on the same branch
|
||||
// 3) i1 is ordered before i2 on the same segment
|
||||
bool PLTRecordMSW::OrderSegConns::operator()(const int i1, const int i2) const
|
||||
{
|
||||
const auto si1 = this->segIdx(i1);
|
||||
const auto si2 = this->segIdx(i2);
|
||||
|
||||
const auto b1 = this->brnNum(si1);
|
||||
const auto b2 = this->brnNum(si2);
|
||||
|
||||
if (b1 != b2) {
|
||||
// i1 not on same branch as i2. Order by branch number.
|
||||
return b1 < b2;
|
||||
}
|
||||
|
||||
if (si1 != si2) {
|
||||
// i1 and i2 on same branch, but not on same segment. Order by
|
||||
// whether or not i1's segment is before i2's segment.
|
||||
return this->segOrderedBefore_(si1, si2);
|
||||
}
|
||||
|
||||
// If we're here i1 and i2 are on the same segment and,
|
||||
// transitively, on the same branch. Order by tubing distance.
|
||||
return this->connDistance(i1) < this->connDistance(i2);
|
||||
}
|
||||
|
||||
int PLTRecordMSW::OrderSegConns::segNum(const int connIdx) const
|
||||
{
|
||||
return this->wellConns_.get()[connIdx].segment();
|
||||
}
|
||||
|
||||
int PLTRecordMSW::OrderSegConns::segIdx(const int connIdx) const
|
||||
{
|
||||
return this->wellSegs_.get().segmentNumberToIndex(this->segNum(connIdx));
|
||||
}
|
||||
|
||||
int PLTRecordMSW::OrderSegConns::brnNum(const int segIx) const
|
||||
{
|
||||
return this->wellSegs_.get()[segIx].branchNumber();
|
||||
}
|
||||
|
||||
double PLTRecordMSW::OrderSegConns::connDistance(const int connIdx) const
|
||||
{
|
||||
return this->wellConns_.get()[connIdx].perf_range()->second;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
@ -357,7 +970,7 @@ namespace {
|
||||
{
|
||||
public:
|
||||
enum class DataTypes {
|
||||
RFT,
|
||||
RFT, PLT,
|
||||
};
|
||||
|
||||
explicit WellRFTOutputData(const std::vector<DataTypes>& types,
|
||||
@ -388,8 +1001,13 @@ namespace {
|
||||
double elapsed_{};
|
||||
Opm::RestartIO::InteHEAD::TimePoint timeStamp_{};
|
||||
|
||||
// Note: 'rft_' could be an optional<>, but 'plt_' must be a
|
||||
// pointer. We need run-time polymorphic behaviour for 'plt_'. We
|
||||
// therefore use pointers for all of these members, but mostly for
|
||||
// uniformity.
|
||||
std::unique_ptr<WellConnectionRecord> wconns_{};
|
||||
std::unique_ptr<RFTRecord> rft_{};
|
||||
std::unique_ptr<PLTRecord> plt_{};
|
||||
|
||||
std::vector<DataHandler> dataHandlers_{};
|
||||
std::vector<RecordWriter> recordWriters_{};
|
||||
@ -398,8 +1016,11 @@ namespace {
|
||||
|
||||
void initialiseConnHandlers();
|
||||
void initialiseRFTHandlers();
|
||||
void initialisePLTHandlers();
|
||||
|
||||
bool haveOutputData() const;
|
||||
bool haveRFTData() const;
|
||||
bool havePLTData() const;
|
||||
|
||||
void writeHeader(::Opm::EclIO::OutputStream::RFT& rftFile) const;
|
||||
|
||||
@ -434,7 +1055,8 @@ namespace {
|
||||
|
||||
bool WellRFTOutputData::haveOutputData() const
|
||||
{
|
||||
return this->haveRFTData();
|
||||
return this->haveRFTData()
|
||||
|| this->havePLTData();
|
||||
}
|
||||
|
||||
void WellRFTOutputData::addDynamicData(const Opm::data::Well& wellSol)
|
||||
@ -502,12 +1124,44 @@ namespace {
|
||||
});
|
||||
}
|
||||
|
||||
void WellRFTOutputData::initialisePLTHandlers()
|
||||
{
|
||||
const auto& well = this->well_.get();
|
||||
|
||||
if (well.getConnections().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->plt_ = well.isMultiSegment()
|
||||
? std::make_unique<PLTRecordMSW>(well.getConnections().size())
|
||||
: std::make_unique<PLTRecord> (well.getConnections().size());
|
||||
|
||||
this->dataHandlers_.emplace_back(
|
||||
[this](const Opm::data::Well& wellSol)
|
||||
{
|
||||
this->plt_->collectRecordData(this->usys_, this->grid_,
|
||||
this->well_, wellSol);
|
||||
});
|
||||
|
||||
this->recordWriters_.emplace_back(
|
||||
[this](::Opm::EclIO::OutputStream::RFT& rftFile)
|
||||
{
|
||||
this->plt_->write(rftFile);
|
||||
});
|
||||
}
|
||||
|
||||
bool WellRFTOutputData::haveRFTData() const
|
||||
{
|
||||
return (this->rft_ != nullptr)
|
||||
&& (this->rft_->nConn() > std::size_t{0});
|
||||
}
|
||||
|
||||
bool WellRFTOutputData::havePLTData() const
|
||||
{
|
||||
return (this->plt_ != nullptr)
|
||||
&& (this->plt_->nConn() > std::size_t{0});
|
||||
}
|
||||
|
||||
void WellRFTOutputData::writeHeader(::Opm::EclIO::OutputStream::RFT& rftFile) const
|
||||
{
|
||||
{
|
||||
@ -576,6 +1230,7 @@ namespace {
|
||||
{
|
||||
auto tstring = std::string{};
|
||||
if (this->haveRFTData()) { tstring += 'R';}
|
||||
if (this->havePLTData()) { tstring += 'P';}
|
||||
|
||||
return tstring;
|
||||
}
|
||||
@ -590,11 +1245,31 @@ namespace {
|
||||
std::map<WellRFTOutputData::DataTypes, WellRFTOutputData::CreateTypeHandler>
|
||||
WellRFTOutputData::creators_{
|
||||
{ WellRFTOutputData::DataTypes::RFT, &WellRFTOutputData::initialiseRFTHandlers },
|
||||
{ WellRFTOutputData::DataTypes::PLT, &WellRFTOutputData::initialisePLTHandlers },
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
namespace {
|
||||
std::vector<WellRFTOutputData::DataTypes>
|
||||
rftDataTypes(const Opm::RFTConfig& rft_config,
|
||||
const std::string& well_name)
|
||||
{
|
||||
auto rftTypes = std::vector<WellRFTOutputData::DataTypes>{};
|
||||
|
||||
if (rft_config.rft(well_name)) {
|
||||
rftTypes.push_back(WellRFTOutputData::DataTypes::RFT);
|
||||
}
|
||||
|
||||
if (rft_config.plt(well_name)) {
|
||||
rftTypes.push_back(WellRFTOutputData::DataTypes::PLT);
|
||||
}
|
||||
|
||||
return rftTypes;
|
||||
}
|
||||
}
|
||||
|
||||
void Opm::RftIO::write(const int reportStep,
|
||||
const double elapsed,
|
||||
const ::Opm::UnitSystem& usys,
|
||||
@ -605,7 +1280,7 @@ void Opm::RftIO::write(const int reportStep,
|
||||
{
|
||||
const auto& rftCfg = schedule[reportStep].rft_config();
|
||||
if (! rftCfg.active()) {
|
||||
// RFT not yet activated. Nothing to do.
|
||||
// RFT file output not yet activated. Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,14 +1288,10 @@ void Opm::RftIO::write(const int reportStep,
|
||||
getSimulationTimePoint(schedule.getStartTime(), elapsed);
|
||||
|
||||
for (const auto& wname : schedule.wellNames(reportStep)) {
|
||||
auto rftTypes = std::vector<WellRFTOutputData::DataTypes>{};
|
||||
|
||||
if (rftCfg.rft(wname) || rftCfg.plt(wname)) {
|
||||
rftTypes.push_back(WellRFTOutputData::DataTypes::RFT);
|
||||
}
|
||||
const auto rftTypes = rftDataTypes(rftCfg, wname);
|
||||
|
||||
if (rftTypes.empty()) {
|
||||
// RFT output not requested for 'wname' at this time.
|
||||
// RFT file output not requested for 'wname' at this time.
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -630,8 +1301,8 @@ void Opm::RftIO::write(const int reportStep,
|
||||
continue;
|
||||
}
|
||||
|
||||
// RFT output requested for 'wname' at this time and dynamic data is
|
||||
// available. Collect requisite information.
|
||||
// RFT file output requested for 'wname' at this time and dynamic
|
||||
// data is available. Collect requisite information.
|
||||
auto rftOutput = WellRFTOutputData {
|
||||
rftTypes, elapsed, timePoint, usys, grid,
|
||||
schedule[reportStep].wells(wname)
|
||||
@ -639,9 +1310,9 @@ void Opm::RftIO::write(const int reportStep,
|
||||
|
||||
rftOutput.addDynamicData(xwPos->second);
|
||||
|
||||
// Emit RFT record for 'wname'. This transparently handles wells
|
||||
// without connections--e.g., if the well is only connected in
|
||||
// inactive/deactivated cells.
|
||||
// Emit RFT file output record for 'wname'. This transparently
|
||||
// handles wells without connections--e.g., if the well is only
|
||||
// connected in inactive/deactivated cells.
|
||||
rftOutput.write(rftFile);
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,12 @@
|
||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/input/eclipse/Parser/Parser.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
@ -124,49 +127,34 @@ namespace {
|
||||
std::string base_;
|
||||
};
|
||||
|
||||
class RFTRresults
|
||||
class RFTResultIndex
|
||||
{
|
||||
public:
|
||||
explicit RFTRresults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date);
|
||||
explicit RFTResultIndex(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date);
|
||||
|
||||
float depth(const int i, const int j, const int k) const
|
||||
std::size_t operator()(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->depth_[this->conIx(i, j, k)];
|
||||
}
|
||||
auto conIx = this->xConIx_.find(std::make_tuple(i, j, k));
|
||||
if (conIx == this->xConIx_.end()) {
|
||||
BOOST_FAIL("Invalid IJK Tuple (" << i << ", "
|
||||
<< j << ", " << k << ')');
|
||||
}
|
||||
|
||||
float pressure(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->press_[this->conIx(i, j, k)];
|
||||
}
|
||||
|
||||
float sgas(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->sgas_[this->conIx(i, j, k)];
|
||||
}
|
||||
|
||||
float swat(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->swat_[this->conIx(i, j, k)];
|
||||
return conIx->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<float> depth_;
|
||||
std::vector<float> press_;
|
||||
std::vector<float> sgas_;
|
||||
std::vector<float> swat_;
|
||||
|
||||
std::map<std::tuple<int, int, int>, std::size_t> xConIx_;
|
||||
|
||||
std::size_t conIx(const int i, const int j, const int k) const;
|
||||
};
|
||||
|
||||
RFTRresults::RFTRresults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date)
|
||||
RFTResultIndex::RFTResultIndex(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date)
|
||||
{
|
||||
BOOST_REQUIRE(rft.hasRft(well, date));
|
||||
|
||||
BOOST_REQUIRE(rft.hasArray("CONIPOS", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONJPOS", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONKPOS", well, date));
|
||||
@ -176,9 +164,60 @@ namespace {
|
||||
const auto& K = rft.getRft<int>("CONKPOS", well, date);
|
||||
|
||||
for (auto ncon = I.size(), con = 0*ncon; con < ncon; ++con) {
|
||||
this->xConIx_[std::make_tuple(I[con], J[con], K[con])] = con;
|
||||
this->xConIx_.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(I[con], J[con], K[con]),
|
||||
std::forward_as_tuple(con));
|
||||
}
|
||||
}
|
||||
|
||||
class RFTRresults
|
||||
{
|
||||
public:
|
||||
explicit RFTRresults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date);
|
||||
|
||||
float depth(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->depth_);
|
||||
}
|
||||
|
||||
float pressure(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->press_);
|
||||
}
|
||||
|
||||
float sgas(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->sgas_);
|
||||
}
|
||||
|
||||
float swat(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->swat_);
|
||||
}
|
||||
|
||||
private:
|
||||
RFTResultIndex resIx_;
|
||||
|
||||
std::vector<float> depth_{};
|
||||
std::vector<float> press_{};
|
||||
std::vector<float> sgas_{};
|
||||
std::vector<float> swat_{};
|
||||
|
||||
template <typename T, class A>
|
||||
T value(const int i, const int j, const int k,
|
||||
const std::vector<T, A>& vector) const
|
||||
{
|
||||
return vector[ this->resIx_(i, j, k) ];
|
||||
}
|
||||
};
|
||||
|
||||
RFTRresults::RFTRresults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date)
|
||||
: resIx_{ rft, well, date }
|
||||
{
|
||||
BOOST_REQUIRE(rft.hasArray("DEPTH" , well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("PRESSURE", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("SGAS" , well, date));
|
||||
@ -190,16 +229,154 @@ namespace {
|
||||
this->swat_ = rft.getRft<float>("SWAT" , well, date);
|
||||
}
|
||||
|
||||
std::size_t RFTRresults::conIx(const int i, const int j, const int k) const
|
||||
class PLTResults
|
||||
{
|
||||
auto conIx = this->xConIx_.find(std::make_tuple(i, j, k));
|
||||
public:
|
||||
explicit PLTResults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date);
|
||||
|
||||
if (conIx == this->xConIx_.end()) {
|
||||
BOOST_FAIL("Invalid IJK Tuple (" << i << ", "
|
||||
<< j << ", " << k << ')');
|
||||
int next(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->neighbour_id_);
|
||||
}
|
||||
|
||||
return conIx->second;
|
||||
float depth(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->depth_);
|
||||
}
|
||||
|
||||
float pressure(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->press_);
|
||||
}
|
||||
|
||||
float conntrans(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->trans_);
|
||||
}
|
||||
|
||||
float kh(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->kh_);
|
||||
}
|
||||
|
||||
float orat(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->orat_);
|
||||
}
|
||||
|
||||
float wrat(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->wrat_);
|
||||
}
|
||||
|
||||
float grat(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->grat_);
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T, class A>
|
||||
T value(const int i, const int j, const int k,
|
||||
const std::vector<T, A>& vector) const
|
||||
{
|
||||
return vector[ this->resIx_(i, j, k) ];
|
||||
}
|
||||
|
||||
private:
|
||||
RFTResultIndex resIx_;
|
||||
|
||||
std::vector<int> neighbour_id_{};
|
||||
|
||||
std::vector<float> depth_{};
|
||||
std::vector<float> press_{};
|
||||
std::vector<float> trans_{};
|
||||
std::vector<float> kh_{};
|
||||
|
||||
std::vector<float> orat_{};
|
||||
std::vector<float> wrat_{};
|
||||
std::vector<float> grat_{};
|
||||
};
|
||||
|
||||
PLTResults::PLTResults(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date)
|
||||
: resIx_{ rft, well, date }
|
||||
{
|
||||
BOOST_REQUIRE(rft.hasArray("CONNXT" , well, date));
|
||||
|
||||
BOOST_REQUIRE(rft.hasArray("CONDEPTH", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONPRES" , well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONFAC" , well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONKH" , well, date));
|
||||
|
||||
BOOST_REQUIRE(rft.hasArray("CONORAT" , well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONWRAT" , well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONGRAT" , well, date));
|
||||
|
||||
this->neighbour_id_ = rft.getRft<int>("CONNXT", well, date);
|
||||
|
||||
this->depth_ = rft.getRft<float>("CONDEPTH", well, date);
|
||||
this->press_ = rft.getRft<float>("CONPRES" , well, date);
|
||||
this->trans_ = rft.getRft<float>("CONFAC" , well, date);
|
||||
this->kh_ = rft.getRft<float>("CONKH" , well, date);
|
||||
|
||||
this->orat_ = rft.getRft<float>("CONORAT", well, date);
|
||||
this->wrat_ = rft.getRft<float>("CONWRAT", well, date);
|
||||
this->grat_ = rft.getRft<float>("CONGRAT", well, date);
|
||||
}
|
||||
|
||||
class PLTResultsMSW : public PLTResults
|
||||
{
|
||||
public:
|
||||
explicit PLTResultsMSW(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date);
|
||||
|
||||
int segment(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->segment_id_);
|
||||
}
|
||||
|
||||
int branch(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->branch_id_);
|
||||
}
|
||||
|
||||
float start(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->start_length_);
|
||||
}
|
||||
|
||||
float end(const int i, const int j, const int k) const
|
||||
{
|
||||
return this->value(i, j, k, this->end_length_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<int> segment_id_{};
|
||||
std::vector<int> branch_id_{};
|
||||
|
||||
std::vector<float> start_length_{};
|
||||
std::vector<float> end_length_{};
|
||||
};
|
||||
|
||||
PLTResultsMSW::PLTResultsMSW(const ::Opm::EclIO::ERft& rft,
|
||||
const std::string& well,
|
||||
const ::Opm::EclIO::ERft::RftDate& date)
|
||||
: PLTResults{ rft, well, date }
|
||||
{
|
||||
BOOST_REQUIRE(rft.hasArray("CONLENST", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONLENEN", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONSEGNO", well, date));
|
||||
BOOST_REQUIRE(rft.hasArray("CONBRNO" , well, date));
|
||||
|
||||
this->segment_id_ = rft.getRft<int>("CONSEGNO", well, date);
|
||||
this->branch_id_ = rft.getRft<int>("CONBRNO" , well, date);
|
||||
|
||||
this->start_length_ = rft.getRft<float>("CONLENST", well, date);
|
||||
this->end_length_ = rft.getRft<float>("CONLENEN", well, date);
|
||||
}
|
||||
|
||||
void verifyRFTFile(const std::string& rft_filename)
|
||||
@ -2457,3 +2634,656 @@ BOOST_AUTO_TEST_CASE(PVT_M_Units)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // Using_Direct_Write
|
||||
|
||||
// =====================================================================
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PLTData)
|
||||
|
||||
namespace {
|
||||
Opm::Deck pltDataSet()
|
||||
{
|
||||
return ::Opm::Parser{}.parseString(R"(RUNSPEC
|
||||
TITLE
|
||||
'BASE1' 'MSW' 'HFA'
|
||||
|
||||
NOECHO
|
||||
|
||||
DIMENS
|
||||
6 8 7 /
|
||||
|
||||
START
|
||||
1 'JAN' 2000 /
|
||||
|
||||
OIL
|
||||
WATER
|
||||
GAS
|
||||
DISGAS
|
||||
VAPOIL
|
||||
METRIC
|
||||
|
||||
TABDIMS
|
||||
1 1 5 20 1* 20 /
|
||||
|
||||
EQLDIMS
|
||||
1 /
|
||||
|
||||
REGDIMS
|
||||
1 1 /
|
||||
|
||||
WELLDIMS
|
||||
2 7 2 2 /
|
||||
|
||||
WSEGDIMS
|
||||
1 12 1 /
|
||||
|
||||
UNIFIN
|
||||
UNIFOUT
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
GRID
|
||||
|
||||
GRIDFILE
|
||||
0 1 /
|
||||
|
||||
INIT
|
||||
NEWTRAN
|
||||
|
||||
GRIDUNIT
|
||||
'METRES' /
|
||||
|
||||
SPECGRID
|
||||
6 8 7 1 'F' /
|
||||
|
||||
DXV
|
||||
6*100 /
|
||||
|
||||
DYV
|
||||
8*100 /
|
||||
|
||||
DZV
|
||||
7*10 /
|
||||
|
||||
DEPTHZ
|
||||
63*2700 /
|
||||
|
||||
PERMX
|
||||
48*72 48*135 48*355 48*50 48*200 48*130 48*55 /
|
||||
|
||||
PORO
|
||||
48*0.25 48*0.2 48*0.2 48*0.2 48*0.2 48*0.18 48*0.18 /
|
||||
|
||||
COPY
|
||||
'PERMX' 'PERMY' /
|
||||
'PERMX' 'PERMZ' /
|
||||
/
|
||||
|
||||
MULTIPLY
|
||||
'PERMZ' 0.1 /
|
||||
/
|
||||
|
||||
MULTZ
|
||||
48*1 48*1 48*1
|
||||
48*0
|
||||
48*1 48*1 48*1 /
|
||||
|
||||
MULTNUM
|
||||
48*1 48*1
|
||||
48*2 48*2 48*2
|
||||
48*3 48*3 /
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
PROPS
|
||||
|
||||
SWOF
|
||||
0 0 1 0
|
||||
1 1 0 0 /
|
||||
|
||||
SGOF
|
||||
0 0 1 0
|
||||
1 1 0 0 /
|
||||
|
||||
ROCK
|
||||
280 5.6e-05 /
|
||||
|
||||
PVTW
|
||||
247.7 1.03665 4.1726e-05 0.2912 9.9835e-05 /
|
||||
|
||||
DENSITY
|
||||
861 999.1 1.01735 /
|
||||
|
||||
PVTO
|
||||
0 1 1.07033 0.645
|
||||
25 1.06657 0.668
|
||||
50 1.06293 0.691
|
||||
75 1.05954 0.714
|
||||
100 1.05636 0.736 /
|
||||
|
||||
17.345 25 1.14075 0.484
|
||||
50 1.1351 0.506
|
||||
75 1.12989 0.527
|
||||
100 1.12508 0.548 /
|
||||
|
||||
31.462 50 1.1843 0.439
|
||||
75 1.178 0.459
|
||||
100 1.17219 0.479 /
|
||||
|
||||
45.089 75 1.22415 0.402
|
||||
100 1.21728 0.421
|
||||
150 1.2051 0.458
|
||||
200 1.19461 0.494 /
|
||||
|
||||
58.99 100 1.26373 0.37
|
||||
150 1.24949 0.405
|
||||
200 1.23732 0.439
|
||||
225 1.23186 0.456 /
|
||||
|
||||
88.618 150 1.34603 0.316
|
||||
200 1.32975 0.346
|
||||
225 1.32253 0.361
|
||||
250 1.31582 0.376 /
|
||||
|
||||
120.85 200 1.43292 0.273
|
||||
225 1.42343 0.286
|
||||
250 1.41467 0.299
|
||||
275 1.40656 0.312 /
|
||||
|
||||
138.134 225 1.47867 0.255
|
||||
250 1.46868 0.267
|
||||
275 1.45945 0.279
|
||||
294.6 1.45269 0.288 /
|
||||
|
||||
156.324 250 1.52632 0.239
|
||||
275 1.51583 0.25
|
||||
294.6 1.50816 0.258
|
||||
300 1.50613 0.261 /
|
||||
|
||||
175.509 275 1.5761 0.224
|
||||
294.6 1.56741 0.232
|
||||
300 1.5651 0.234
|
||||
324 1.55533 0.244 /
|
||||
|
||||
191.323 294.6 1.61682 0.214
|
||||
300 1.61428 0.216
|
||||
324 1.60352 0.225
|
||||
350 1.59271 0.235 /
|
||||
|
||||
195.818 300 1.62835 0.211
|
||||
324 1.6173 0.22
|
||||
350 1.60621 0.23
|
||||
400 1.58707 0.248 /
|
||||
|
||||
216.43 324 1.68095 0.199
|
||||
350 1.66851 0.208
|
||||
400 1.64713 0.226
|
||||
450 1.62847 0.243
|
||||
500 1.612 0.26 /
|
||||
/
|
||||
|
||||
PVTG
|
||||
1 2.123e-06 1.877001 0.01037
|
||||
0 1.352546 0.011247 /
|
||||
25 5.99e-06 0.050493 0.012925
|
||||
0 0.050477 0.012932 /
|
||||
50 4.9422e-06 0.024609 0.01373
|
||||
0 0.024612 0.013734 /
|
||||
75 6.1628e-06 0.016094 0.014475
|
||||
0 0.016102 0.014475 /
|
||||
100 8.6829e-06 0.011902 0.015347
|
||||
0 0.011915 0.015334 /
|
||||
150 1.91019e-05 0.007838 0.017699
|
||||
0 0.00786 0.017591 /
|
||||
200 4.14858e-05 0.005938 0.020947
|
||||
0 0.005967 0.020506 /
|
||||
225 5.95434e-05 0.005349 0.022888
|
||||
0 0.005377 0.022116 /
|
||||
250 8.3633e-05 0.004903 0.025025
|
||||
0 0.004925 0.023767 /
|
||||
275 0.0001148977 0.004561 0.027355
|
||||
0 0.004571 0.025418 /
|
||||
294.6 0.0001452455 0.00435 0.029325
|
||||
0 0.004344 0.026696 /
|
||||
300 0.0001546223 0.004299 0.029893
|
||||
0 0.004288 0.027044 /
|
||||
324 0.000202062 0.004107 0.032559
|
||||
0.0001546223 0.004098 0.031456
|
||||
0.0001452455 0.004097 0.031237
|
||||
0.0001148977 0.004093 0.030521
|
||||
8.3633e-05 0.004089 0.029767
|
||||
5.95434e-05 0.004088 0.029165
|
||||
4.14858e-05 0.004087 0.028702
|
||||
1.91019e-05 0.004085 0.028173
|
||||
8.6829e-06 0.004068 0.028353
|
||||
0 0.004066 0.028567 /
|
||||
/
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
REGIONS
|
||||
|
||||
SATNUM
|
||||
48*1 48*1 48*1 48*1 48*1 48*1 48*1 /
|
||||
|
||||
EQLNUM
|
||||
48*1 48*1 48*1 48*1 48*1 48*1 48*1 /
|
||||
|
||||
PVTNUM
|
||||
48*1 48*1 48*1 48*1 48*1 48*1 48*1 /
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
SOLUTION
|
||||
|
||||
EQUIL
|
||||
2730 300 2750 0 1650 0 1 1 0 /
|
||||
|
||||
RSVD
|
||||
2650 156.324
|
||||
2750 138.134 /
|
||||
|
||||
RVVD
|
||||
2600 0.00739697
|
||||
2750 0.00639697 /
|
||||
|
||||
RPTSOL
|
||||
'THPRES' 'FIP=2' /
|
||||
|
||||
RPTRST
|
||||
'BASIC=5' FREQ=6 /
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
SUMMARY
|
||||
|
||||
ALL
|
||||
|
||||
-- =====================================================================
|
||||
|
||||
SCHEDULE
|
||||
|
||||
GRUPTREE
|
||||
'TEST' 'FIELD' /
|
||||
/
|
||||
|
||||
WELSPECS
|
||||
'P1' 'TEST' 1 2 1* 'OIL' 0 'STD' 'STOP' 'YES' 0 'SEG' 0 /
|
||||
'I1' 'TEST' 6 8 1* 'WATER' /
|
||||
/
|
||||
|
||||
COMPDAT
|
||||
'P1' 2 3 2 2 'OPEN' 1* 52.08337 0.216 1* 0 1* 'Z' /
|
||||
'P1' 2 3 3 3 'OPEN' 1* 366.2544 0.216 1* 0 1* 'Y' /
|
||||
'P1' 2 4 3 3 'OPEN' 1* 388.4829 0.216 1* 0 1* 'Y' /
|
||||
'P1' 3 4 3 3 'OPEN' 1* 203.6268 0.216 1* 0 1* 'Y' /
|
||||
'P1' 3 5 3 3 'OPEN' 1* 571.7222 0.216 1* 0 1* 'Y' /
|
||||
'P1' 3 6 3 3 'OPEN' 1* 389.4535 0.216 1* 0 1* 'Y' /
|
||||
'I1' 6 8 5 7 'OPEN' 1* 1* 0.216 1* 0 1* 'Z' /
|
||||
/
|
||||
|
||||
WELSEGS
|
||||
'P1' 2620.17107 0 1* 'INC' 'HFA' /
|
||||
2 2 1 1 38.17432 3.32249 0.102 1e-05 /
|
||||
3 3 1 2 62.22322 5.41558 0.102 1e-05 /
|
||||
4 4 1 3 54.33161 4.72874 0.102 1e-05 /
|
||||
5 5 1 4 119.18735 10.34614 0.102 1e-05 /
|
||||
6 6 1 5 263.64361 14.87775 0.102 1e-05 /
|
||||
7 7 1 6 360.47928 11.28317 0.102 1e-05 /
|
||||
8 8 1 7 282.92022 5.30723 0.102 1e-05 /
|
||||
9 9 1 8 370.26595 5.85843 0.102 1e-05 /
|
||||
10 10 1 9 458.85844 9.23286 0.102 1e-05 /
|
||||
11 11 1 10 266.98559 6.56172 0.102 1e-05 /
|
||||
/
|
||||
|
||||
COMPSEGS
|
||||
'P1' /
|
||||
2 3 2 1 233.61 362.82114 /
|
||||
2 3 3 1 362.82114 712.29909 /
|
||||
2 4 3 1 712.29909 1083.7797 /
|
||||
3 4 3 1 1083.7797 1278.13953 /
|
||||
3 5 3 1 1278.13953 1824.3116 /
|
||||
3 6 3 1 1824.3116 2195.85641 /
|
||||
/
|
||||
|
||||
WCONPROD
|
||||
'P1' 'OPEN' 'ORAT' 8000 4* 65 /
|
||||
/
|
||||
|
||||
WCONINJE
|
||||
'I1' 'WATER' 'OPEN' 'RATE' 5000 1* 450 /
|
||||
/
|
||||
|
||||
TSTEP
|
||||
1 /
|
||||
|
||||
WRFTPLT
|
||||
'P1' 'YES' 'YES' 'NO' /
|
||||
'I1' 'YES' 'YES' 'NO' /
|
||||
/
|
||||
|
||||
TSTEP
|
||||
2 3 5 10*10 20*20 30*30 /
|
||||
|
||||
END
|
||||
|
||||
)");
|
||||
}
|
||||
|
||||
std::vector<int> cellIndex(const ::Opm::EclipseGrid& grid,
|
||||
const std::vector<std::array<int,3>>& ijk)
|
||||
{
|
||||
auto cellIx = std::vector<int>{};
|
||||
cellIx.reserve(ijk.size());
|
||||
|
||||
std::transform(ijk.begin(), ijk.end(), std::back_inserter(cellIx),
|
||||
[&grid](const auto& ijk_entry)
|
||||
{
|
||||
return grid.getGlobalIndex(ijk_entry[0] - 1,
|
||||
ijk_entry[1] - 1,
|
||||
ijk_entry[2] - 1);
|
||||
});
|
||||
|
||||
return cellIx;
|
||||
}
|
||||
|
||||
std::vector<int> cellIndex_P1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
return cellIndex(grid, {
|
||||
{2, 3, 2},
|
||||
{2, 3, 3},
|
||||
{2, 4, 3},
|
||||
{3, 4, 3},
|
||||
{3, 5, 3},
|
||||
{3, 6, 3},
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<int> cellIndex_I1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
return cellIndex(grid, {
|
||||
{6, 8, 5},
|
||||
{6, 8, 6},
|
||||
{6, 8, 7},
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<Opm::data::Connection>
|
||||
connRes_P1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
using rt = ::Opm::data::Rates::opt;
|
||||
|
||||
const auto cellIx = cellIndex_P1(grid);
|
||||
|
||||
const auto ncon = static_cast<int>(cellIx.size());
|
||||
|
||||
auto xcon = std::vector<Opm::data::Connection>{};
|
||||
xcon.reserve(ncon);
|
||||
|
||||
const auto m3_d = ::Opm::UnitSystem::newMETRIC()
|
||||
.to_si(::Opm::UnitSystem::measure::liquid_surface_rate, 1.0);
|
||||
|
||||
const auto m3cp_db = ::Opm::UnitSystem::newMETRIC()
|
||||
.to_si(::Opm::UnitSystem::measure::transmissibility, 1.0);
|
||||
|
||||
for (auto con = 0; con < ncon; ++con) {
|
||||
auto& c = xcon.emplace_back();
|
||||
|
||||
c.index = cellIx[con];
|
||||
|
||||
c.cell_pressure = (120 + con*10)*::Opm::unit::barsa;
|
||||
c.pressure = (120 - (ncon - con)*10)*::Opm::unit::barsa;
|
||||
|
||||
// Negative rates for producing connections
|
||||
c.rates.set(rt::oil, - 100*con*m3_d)
|
||||
.set(rt::gas, - 1000*con*m3_d)
|
||||
.set(rt::wat, - 10*con*m3_d);
|
||||
|
||||
c.cell_saturation_gas = 0.15;
|
||||
c.cell_saturation_water = 0.3 + con/static_cast<double>(2 * ncon);
|
||||
c.trans_factor = 0.98765*m3cp_db;
|
||||
}
|
||||
|
||||
return xcon;
|
||||
}
|
||||
|
||||
::Opm::data::Well wellSol_P1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
auto xw = ::Opm::data::Well{};
|
||||
xw.connections = connRes_P1(grid);
|
||||
|
||||
return xw;
|
||||
}
|
||||
|
||||
std::vector<Opm::data::Connection>
|
||||
connRes_I1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
using rt = ::Opm::data::Rates::opt;
|
||||
|
||||
const auto cellIx = cellIndex_I1(grid);
|
||||
|
||||
const auto ncon = static_cast<int>(cellIx.size());
|
||||
|
||||
auto xcon = std::vector<Opm::data::Connection>{};
|
||||
xcon.reserve(ncon);
|
||||
|
||||
const auto m3_d = ::Opm::UnitSystem::newMETRIC()
|
||||
.to_si(::Opm::UnitSystem::measure::liquid_surface_rate, 1.0);
|
||||
|
||||
const auto m3cp_db = ::Opm::UnitSystem::newMETRIC()
|
||||
.to_si(::Opm::UnitSystem::measure::transmissibility, 1.0);
|
||||
|
||||
for (auto con = 0; con < ncon; ++con) {
|
||||
auto& c = xcon.emplace_back();
|
||||
|
||||
c.index = cellIx[con];
|
||||
|
||||
c.cell_pressure = (120 + con*10)*::Opm::unit::barsa;
|
||||
c.pressure = (120 + (3 + con)*10)*::Opm::unit::barsa;
|
||||
|
||||
// Positive rates for injecting connections
|
||||
c.rates.set(rt::wat, 123.4*con*m3_d);
|
||||
|
||||
c.cell_saturation_gas = 0.6 - (con + 3)/static_cast<double>(2 * ncon);
|
||||
c.cell_saturation_water = 0.25;
|
||||
c.trans_factor = 0.12345*m3cp_db;
|
||||
}
|
||||
|
||||
return xcon;
|
||||
}
|
||||
|
||||
::Opm::data::Well wellSol_I1(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
auto xw = ::Opm::data::Well{};
|
||||
xw.connections = connRes_I1(grid);
|
||||
|
||||
return xw;
|
||||
}
|
||||
|
||||
::Opm::data::Wells wellSol(const ::Opm::EclipseGrid& grid)
|
||||
{
|
||||
auto xw = ::Opm::data::Wells{};
|
||||
|
||||
xw["P1"] = wellSol_P1(grid);
|
||||
xw["I1"] = wellSol_I1(grid);
|
||||
|
||||
return xw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Standard_Well)
|
||||
{
|
||||
using RftDate = ::Opm::EclIO::ERft::RftDate;
|
||||
|
||||
const auto rset = RSet { "TESTPLT" };
|
||||
const auto model = Setup{ pltDataSet() };
|
||||
|
||||
{
|
||||
auto rftFile = ::Opm::EclIO::OutputStream::RFT {
|
||||
rset, ::Opm::EclIO::OutputStream::Formatted { false },
|
||||
::Opm::EclIO::OutputStream::RFT::OpenExisting{ false }
|
||||
};
|
||||
|
||||
const auto reportStep = 1;
|
||||
const auto elapsed = model.sched.seconds(reportStep);
|
||||
const auto& grid = model.es.getInputGrid();
|
||||
|
||||
::Opm::RftIO::write(reportStep, elapsed, model.es.getUnits(),
|
||||
grid, model.sched, wellSol(grid), rftFile);
|
||||
}
|
||||
|
||||
const auto rft = ::Opm::EclIO::ERft {
|
||||
::Opm::EclIO::OutputStream::outputFileName(rset, "RFT")
|
||||
};
|
||||
|
||||
const auto xPLT = PLTResults {
|
||||
rft, "I1", RftDate{ 2000, 1, 2 }
|
||||
};
|
||||
|
||||
BOOST_CHECK_EQUAL(xPLT.next(6, 8, 5), 0);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(6, 8, 6), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(6, 8, 7), 2);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(6, 8, 5), 2745.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(6, 8, 6), 2755.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(6, 8, 7), 2765.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(6, 8, 5), 150.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(6, 8, 6), 160.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(6, 8, 7), 170.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(6, 8, 5), 0.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(6, 8, 6), 0.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(6, 8, 7), 0.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(6, 8, 5), 0.0f * (- 123.4f), 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(6, 8, 6), 1.0f * (- 123.4f), 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(6, 8, 7), 2.0f * (- 123.4f), 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(6, 8, 5), 0.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(6, 8, 6), 0.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(6, 8, 7), 0.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(6, 8, 5), 0.12345f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(6, 8, 6), 0.12345f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(6, 8, 7), 0.12345f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(6, 8, 5), 2000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(6, 8, 6), 1300.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(6, 8, 7), 550.0f, 1.0e-5f);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Multisegment_Well)
|
||||
{
|
||||
using RftDate = ::Opm::EclIO::ERft::RftDate;
|
||||
|
||||
const auto rset = RSet { "TESTPLT" };
|
||||
const auto model = Setup{ pltDataSet() };
|
||||
|
||||
{
|
||||
auto rftFile = ::Opm::EclIO::OutputStream::RFT {
|
||||
rset, ::Opm::EclIO::OutputStream::Formatted { false },
|
||||
::Opm::EclIO::OutputStream::RFT::OpenExisting{ false }
|
||||
};
|
||||
|
||||
const auto reportStep = 1;
|
||||
const auto elapsed = model.sched.seconds(reportStep);
|
||||
const auto& grid = model.es.getInputGrid();
|
||||
|
||||
::Opm::RftIO::write(reportStep, elapsed, model.es.getUnits(),
|
||||
grid, model.sched, wellSol(grid), rftFile);
|
||||
}
|
||||
|
||||
const auto rft = ::Opm::EclIO::ERft {
|
||||
::Opm::EclIO::OutputStream::outputFileName(rset, "RFT")
|
||||
};
|
||||
|
||||
const auto xPLT = PLTResultsMSW {
|
||||
rft, "P1", RftDate{ 2000, 1, 2 }
|
||||
};
|
||||
|
||||
BOOST_CHECK_EQUAL(xPLT.next(2, 3, 2), 0);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(2, 3, 3), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(2, 4, 3), 2);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(3, 4, 3), 3);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(3, 5, 3), 4);
|
||||
BOOST_CHECK_EQUAL(xPLT.next(3, 6, 3), 5);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(2, 3, 2), 2645.3552f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(2, 3, 3), 2658.8618f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(2, 4, 3), 2670.1450f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(3, 4, 3), 2675.4521f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(3, 5, 3), 2681.3105f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.depth(3, 6, 3), 2690.5435f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(2, 3, 2), 60.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(2, 3, 3), 70.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(2, 4, 3), 80.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(3, 4, 3), 90.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(3, 5, 3), 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.pressure(3, 6, 3), 110.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(2, 3, 2), 0.0f * 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(2, 3, 3), 1.0f * 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(2, 4, 3), 2.0f * 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(3, 4, 3), 3.0f * 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(3, 5, 3), 4.0f * 100.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.orat(3, 6, 3), 5.0f * 100.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(2, 3, 2), 0.0f * 10.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(2, 3, 3), 1.0f * 10.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(2, 4, 3), 2.0f * 10.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(3, 4, 3), 3.0f * 10.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(3, 5, 3), 4.0f * 10.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.wrat(3, 6, 3), 5.0f * 10.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(2, 3, 2), 0.0f * 1000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(2, 3, 3), 1.0f * 1000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(2, 4, 3), 2.0f * 1000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(3, 4, 3), 3.0f * 1000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(3, 5, 3), 4.0f * 1000.0f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.grat(3, 6, 3), 5.0f * 1000.0f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(2, 3, 2), 0.98765f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(2, 3, 3), 0.98765f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(2, 4, 3), 0.98765f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(3, 4, 3), 0.98765f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(3, 5, 3), 0.98765f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.conntrans(3, 6, 3), 0.98765f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(2, 3, 2), 5.0659907e3f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(2, 3, 3), 2.8570773e4f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(2, 4, 3), 3.0304773e4f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(3, 4, 3), 1.5884520e4f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(3, 5, 3), 4.4598906e4f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.kh(3, 6, 3), 3.0380488e4f, 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(2, 3, 2), 5);
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(2, 3, 3), 6);
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(2, 4, 3), 7);
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(3, 4, 3), 8);
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(3, 5, 3), 9);
|
||||
BOOST_CHECK_EQUAL(xPLT.segment(3, 6, 3), 10);
|
||||
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(2, 3, 2), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(2, 3, 3), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(2, 4, 3), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(3, 4, 3), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(3, 5, 3), 1);
|
||||
BOOST_CHECK_EQUAL(xPLT.branch(3, 6, 3), 1);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.start(2, 3, 2), 233.61f , 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.start(2, 3, 3), 362.82114f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.start(2, 4, 3), 712.29909f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.start(3, 4, 3), 1083.7797f , 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.start(3, 5, 3), 1278.13953f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.start(3, 6, 3), 1824.3116f , 1.0e-5f);
|
||||
|
||||
BOOST_CHECK_CLOSE(xPLT.end(2, 3, 2), 362.82114f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.end(2, 3, 3), 712.29909f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.end(2, 4, 3), 1083.7797f , 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.end(3, 4, 3), 1278.13953f, 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.end(3, 5, 3), 1824.3116f , 1.0e-5f);
|
||||
BOOST_CHECK_CLOSE(xPLT.end(3, 6, 3), 2195.85641f, 1.0e-5f);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // PLTData
|
||||
|
Loading…
Reference in New Issue
Block a user