mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#1994 Update opm-flowdiagnostics-applications to cd614100f3d5b8fcf1fd783e929630f11251682e
This commit is contained in:
parent
5efd583390
commit
2a41b4fbb8
@ -14,7 +14,7 @@ set(ERT_GITHUB_SHA "2e36798b43daf18c112b91aa3febbf2fccd4a95f")
|
||||
set(OPM_FLOWDIAGNOSTICS_SHA "7e2be931d430796ed42efcfb5c6b67a8d5962f7f")
|
||||
|
||||
# https://github.com/OPM/opm-flowdiagnostics-applications
|
||||
set(OPM_FLOWDIAGNOSTICS_APPLICATIONS_SHA "75b333335f6cd055d3130d460c6d87444fb7aed4")
|
||||
set(OPM_FLOWDIAGNOSTICS_APPLICATIONS_SHA "cd614100f3d5b8fcf1fd783e929630f11251682e")
|
||||
|
||||
# https://github.com/OPM/opm-parser/blob/master/opm/parser/eclipse/Units/Units.hpp
|
||||
# This file was moved from opm-core to opm-parser october 2016
|
||||
|
@ -25,6 +25,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/utility/ECLEndPointScaling.cpp
|
||||
opm/utility/ECLFluxCalc.cpp
|
||||
opm/utility/ECLGraph.cpp
|
||||
opm/utility/ECLPropertyUnitConversion.cpp
|
||||
opm/utility/ECLPropTable.cpp
|
||||
opm/utility/ECLPvtCommon.cpp
|
||||
opm/utility/ECLPvtCurveCollection.cpp
|
||||
@ -41,6 +42,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
|
||||
list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_eclendpointscaling.cpp
|
||||
tests/test_eclpropertyunitconversion.cpp
|
||||
tests/test_eclproptable.cpp
|
||||
tests/test_eclpvtcommon.cpp
|
||||
tests/test_eclregionmapping.cpp
|
||||
@ -54,6 +56,7 @@ list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/computePhaseFluxes.cpp
|
||||
examples/computeToFandTracers.cpp
|
||||
examples/computeTracers.cpp
|
||||
examples/dynamicCellProperty.cpp
|
||||
examples/extractFromRestart.cpp
|
||||
examples/extractPropCurves.cpp
|
||||
tests/runAcceptanceTest.cpp
|
||||
@ -68,6 +71,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/utility/ECLGraph.hpp
|
||||
opm/utility/ECLPhaseIndex.hpp
|
||||
opm/utility/ECLPiecewiseLinearInterpolant.hpp
|
||||
opm/utility/ECLPropertyUnitConversion.hpp
|
||||
opm/utility/ECLPropTable.hpp
|
||||
opm/utility/ECLPvtCommon.hpp
|
||||
opm/utility/ECLPvtCurveCollection.hpp
|
||||
|
273
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/examples/dynamicCellProperty.cpp
vendored
Normal file
273
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/examples/dynamicCellProperty.cpp
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <examples/exampleSetup.hpp>
|
||||
|
||||
#include <opm/utility/ECLCaseUtilities.hpp>
|
||||
#include <opm/utility/ECLPhaseIndex.hpp>
|
||||
#include <opm/utility/ECLPvtCommon.hpp>
|
||||
#include <opm/utility/ECLPvtCurveCollection.hpp>
|
||||
#include <opm/utility/ECLResultData.hpp>
|
||||
#include <opm/utility/ECLUnitHandling.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace {
|
||||
void openRestartSet(const Opm::ECLCaseUtilities::ResultSet& rset,
|
||||
const int step,
|
||||
std::unique_ptr<Opm::ECLRestartData>& rstrt)
|
||||
{
|
||||
if (! (rset.isUnifiedRestart() && rstrt)) {
|
||||
// Not a unified restart file or this is the first time we're
|
||||
// seeing the result set.
|
||||
rstrt.reset(new Opm::ECLRestartData(rset.restartFile(step)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CellState
|
||||
{
|
||||
CellState(const Opm::ECLGraph& G,
|
||||
const Opm::ECLCaseUtilities::ResultSet& rset,
|
||||
const int cellID_);
|
||||
|
||||
int cellID;
|
||||
std::vector<double> time;
|
||||
std::vector<double> Po;
|
||||
std::vector<double> Rs;
|
||||
std::vector<double> Rv;
|
||||
};
|
||||
|
||||
CellState::CellState(const Opm::ECLGraph& G,
|
||||
const Opm::ECLCaseUtilities::ResultSet& rset,
|
||||
const int cellID_)
|
||||
: cellID(cellID_)
|
||||
{
|
||||
const auto rsteps = rset.reportStepIDs();
|
||||
|
||||
this->time.reserve(rsteps.size());
|
||||
this->Po .reserve(rsteps.size());
|
||||
this->Rs .reserve(rsteps.size());
|
||||
this->Rv .reserve(rsteps.size());
|
||||
|
||||
auto rstrt = std::unique_ptr<Opm::ECLRestartData>{};
|
||||
|
||||
for (const auto& step : rsteps) {
|
||||
openRestartSet(rset, step, rstrt);
|
||||
|
||||
rstrt->selectReportStep(step);
|
||||
|
||||
this->time.push_back(example::simulationTime(*rstrt));
|
||||
|
||||
{
|
||||
const auto& press =
|
||||
G.rawLinearisedCellData<double>(*rstrt, "PRESSURE");
|
||||
|
||||
this->Po.push_back(press[cellID]);
|
||||
}
|
||||
|
||||
{
|
||||
const auto& R =
|
||||
G.rawLinearisedCellData<double>(*rstrt, "RS");
|
||||
|
||||
this->Rs.push_back(R.empty() ? 0.0 : R[cellID]);
|
||||
}
|
||||
|
||||
{
|
||||
const auto& R =
|
||||
G.rawLinearisedCellData<double>(*rstrt, "RV");
|
||||
|
||||
this->Rv.push_back(R.empty() ? 0.0 : R[cellID]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Property
|
||||
{
|
||||
std::string name;
|
||||
std::vector<double> data;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Gas Properties
|
||||
|
||||
std::vector<double>
|
||||
Bg(const Opm::ECLPVT::ECLPvtCurveCollection& pvtCC,
|
||||
const CellState& x)
|
||||
{
|
||||
using RC = Opm::ECLPVT::RawCurve;
|
||||
using PI = Opm::ECLPhaseIndex;
|
||||
|
||||
return pvtCC.getDynamicPropertyNative(RC::FVF, PI::Vapour,
|
||||
x.cellID, x.Po, x.Rv);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
mu_g(const Opm::ECLPVT::ECLPvtCurveCollection& pvtCC,
|
||||
const CellState& x)
|
||||
{
|
||||
using RC = Opm::ECLPVT::RawCurve;
|
||||
using PI = Opm::ECLPhaseIndex;
|
||||
|
||||
return pvtCC.getDynamicPropertyNative(RC::Viscosity, PI::Vapour,
|
||||
x.cellID, x.Po, x.Rv);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Oil Properties
|
||||
|
||||
std::vector<double>
|
||||
Bo(const Opm::ECLPVT::ECLPvtCurveCollection& pvtCC,
|
||||
const CellState& x)
|
||||
{
|
||||
using RC = Opm::ECLPVT::RawCurve;
|
||||
using PI = Opm::ECLPhaseIndex;
|
||||
|
||||
return pvtCC.getDynamicPropertyNative(RC::FVF, PI::Liquid,
|
||||
x.cellID, x.Po, x.Rs);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
mu_o(const Opm::ECLPVT::ECLPvtCurveCollection& pvtCC,
|
||||
const CellState& x)
|
||||
{
|
||||
using RC = Opm::ECLPVT::RawCurve;
|
||||
using PI = Opm::ECLPhaseIndex;
|
||||
|
||||
return pvtCC.getDynamicPropertyNative(RC::Viscosity, PI::Liquid,
|
||||
x.cellID, x.Po, x.Rs);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Command-line argument processing and property output.
|
||||
|
||||
using DynProp = std::vector<double>
|
||||
(*)(const Opm::ECLPVT::ECLPvtCurveCollection& pvtCC,
|
||||
const CellState& x);
|
||||
|
||||
std::map<std::string, DynProp> enumerateProperties()
|
||||
{
|
||||
return {
|
||||
{ "Bg" , &Bg },
|
||||
{ "mu_g" , &mu_g },
|
||||
{ "Bo" , &Bo },
|
||||
{ "mu_o" , &mu_o },
|
||||
};
|
||||
}
|
||||
|
||||
void writeVector(const std::vector<double>& x, const std::string& var)
|
||||
{
|
||||
std::cout << var << " = [\n";
|
||||
|
||||
for (const auto& xi : x) {
|
||||
std::cout << " " << xi << '\n';
|
||||
}
|
||||
|
||||
std::cout << "]\n\n";
|
||||
}
|
||||
|
||||
void writeResults(const CellState& x, const std::vector<Property>& props)
|
||||
{
|
||||
writeVector(x.time, "time");
|
||||
writeVector(x.Po , "Po");
|
||||
writeVector(x.Rs , "Rs");
|
||||
writeVector(x.Rv , "Rv");
|
||||
|
||||
for (const auto& prop : props) {
|
||||
writeVector(prop.data, prop.name);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
makeUnits(const std::string& unit,
|
||||
const Opm::ECLInitFileData& init)
|
||||
{
|
||||
if ((unit == "si") || (unit == "SI") || (unit == "internal")) {
|
||||
return {}; // No conversion needed.
|
||||
}
|
||||
|
||||
if ((unit == "metric") || (unit == "Metric") || (unit == "METRIC")) {
|
||||
return Opm::ECLUnits::metricUnitConventions();
|
||||
}
|
||||
|
||||
if ((unit == "field") || (unit == "Field") || (unit == "FIELD")) {
|
||||
return Opm::ECLUnits::fieldUnitConventions();
|
||||
}
|
||||
|
||||
if ((unit == "lab") || (unit == "Lab") || (unit == "LAB")) {
|
||||
return Opm::ECLUnits::labUnitConventions();
|
||||
}
|
||||
|
||||
if ((unit == "pvt-m") || (unit == "PVT-M") || (unit == "PVTM")) {
|
||||
return Opm::ECLUnits::pvtmUnitConventions();
|
||||
}
|
||||
|
||||
std::cerr << "Unit convention '" << unit << "' not recognized\n"
|
||||
<< "Using 'native' (input/serialised) conventions.\n";
|
||||
|
||||
return Opm::ECLUnits::serialisedUnitConventions(init);
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
try {
|
||||
const auto prm = example::initParam(argc, argv);
|
||||
const auto cellID = prm.getDefault("cell", 0);
|
||||
|
||||
const auto rset = example::identifyResultSet(prm);
|
||||
const auto init = Opm::ECLInitFileData(rset.initFile());
|
||||
const auto graph = Opm::ECLGraph::load(rset.gridFile(), init);
|
||||
|
||||
auto pvtCC = Opm::ECLPVT::ECLPvtCurveCollection(graph, init);
|
||||
if (prm.has("unit")) {
|
||||
pvtCC.setOutputUnits(makeUnits(prm.get<std::string>("unit"), init));
|
||||
}
|
||||
|
||||
const auto x = CellState{ graph, rset, cellID };
|
||||
|
||||
auto props = std::vector<Property>{};
|
||||
|
||||
for (const auto& prop : enumerateProperties()) {
|
||||
if (prm.getDefault(prop.first, false)) {
|
||||
props.push_back(Property{ prop.first, (*prop.second)(pvtCC, x) });
|
||||
}
|
||||
}
|
||||
|
||||
if (! props.empty()) {
|
||||
std::cout.precision(16);
|
||||
std::cout.setf(std::ios_base::scientific);
|
||||
|
||||
writeResults(x, props);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Caught Exception: " << e.what() << '\n';
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -179,6 +179,19 @@ namespace example {
|
||||
|
||||
|
||||
|
||||
inline double simulationTime(const Opm::ECLRestartData& rstrt)
|
||||
{
|
||||
if (! rstrt.haveKeywordData("DOUBHEAD")) {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
const auto& doubhead = rstrt.keywordData<double>("DOUBHEAD");
|
||||
|
||||
// First item (.front()) is simulation time in days
|
||||
return doubhead.front();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline Opm::FlowDiagnostics::Toolbox
|
||||
initToolbox(const Opm::ECLGraph& G)
|
||||
|
@ -0,0 +1,437 @@
|
||||
/*
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/utility/ECLPropertyUnitConversion.hpp>
|
||||
|
||||
#include <opm/utility/ECLResultData.hpp>
|
||||
#include <opm/utility/ECLUnitHandling.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_kw_magic.h>
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace detail {
|
||||
template <class ResultSet>
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
serialisedUnitConventions(const ResultSet& rset)
|
||||
{
|
||||
// Use INTEHEAD from Main grid. Reasonably safe.
|
||||
const auto& ih = rset.template keywordData<int>(INTEHEAD_KW);
|
||||
|
||||
return ::Opm::ECLUnits::createUnitSystem(ih[ INTEHEAD_UNIT_INDEX ]);
|
||||
}
|
||||
|
||||
struct SIUnits : public ::Opm::ECLUnits::UnitSystem
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
clone() const override
|
||||
{
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem> {
|
||||
new SIUnits(*this)
|
||||
};
|
||||
}
|
||||
|
||||
virtual double density() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double depth() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double pressure() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double reservoirRate() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double reservoirVolume() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double surfaceVolumeGas() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double surfaceVolumeLiquid() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double time() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double transmissibility() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
virtual double viscosity() const override
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::serialisedUnitConventions(const ECLRestartData& rstrt)
|
||||
{
|
||||
return detail::serialisedUnitConventions(rstrt);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::serialisedUnitConventions(const ECLInitFileData& init)
|
||||
{
|
||||
return detail::serialisedUnitConventions(init);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::internalUnitConventions()
|
||||
{
|
||||
using UPtr = std::unique_ptr<const UnitSystem>;
|
||||
|
||||
return UPtr{ new detail::SIUnits{} };
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::metricUnitConventions()
|
||||
{
|
||||
return ::Opm::ECLUnits::createUnitSystem(1);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::fieldUnitConventions()
|
||||
{
|
||||
return ::Opm::ECLUnits::createUnitSystem(2);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::labUnitConventions()
|
||||
{
|
||||
return ::Opm::ECLUnits::createUnitSystem(3);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
Opm::ECLUnits::pvtmUnitConventions()
|
||||
{
|
||||
return ::Opm::ECLUnits::createUnitSystem(4);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Class Convert::PhysicalQuantity::Impl
|
||||
// =====================================================================
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
conditionalClone(const Opm::ECLUnits::UnitSystem* usys)
|
||||
{
|
||||
if (usys == nullptr) {
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem>{};
|
||||
}
|
||||
|
||||
return usys->clone();
|
||||
}
|
||||
}
|
||||
|
||||
class Opm::ECLUnits::Convert::PhysicalQuantity::Impl
|
||||
{
|
||||
public:
|
||||
Impl() {}
|
||||
|
||||
Impl(const Impl& rhs)
|
||||
: from_(conditionalClone(rhs.from_.get()))
|
||||
, to_ (conditionalClone(rhs.to_ .get()))
|
||||
{}
|
||||
|
||||
Impl(Impl&& rhs)
|
||||
: from_(std::move(rhs.from_))
|
||||
, to_ (std::move(rhs.to_))
|
||||
{}
|
||||
|
||||
Impl& operator=(const Impl& rhs)
|
||||
{
|
||||
this->from_ = conditionalClone(rhs.from_.get());
|
||||
this->to_ = conditionalClone(rhs.to_ .get());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Impl& operator=(Impl&& rhs)
|
||||
{
|
||||
this->from_ = std::move(rhs.from_);
|
||||
this->to_ = std::move(rhs.to_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from(const UnitSystem& usys)
|
||||
{
|
||||
this->from_ = usys.clone();
|
||||
}
|
||||
|
||||
void to(const UnitSystem& usys)
|
||||
{
|
||||
this->to_ = usys.clone();
|
||||
}
|
||||
|
||||
const UnitSystem* from() const
|
||||
{
|
||||
return this->from_.get();
|
||||
}
|
||||
|
||||
const UnitSystem* to() const
|
||||
{
|
||||
return this->to_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<UnitSystem> from_{ nullptr };
|
||||
std::unique_ptr<UnitSystem> to_ { nullptr };
|
||||
};
|
||||
|
||||
// =====================================================================
|
||||
// Class Convert::PhysicalQuantity
|
||||
// =====================================================================
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::PhysicalQuantity()
|
||||
: pImpl_(new Impl{})
|
||||
{}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::~PhysicalQuantity()
|
||||
{}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::
|
||||
PhysicalQuantity(const PhysicalQuantity& rhs)
|
||||
: pImpl_(new Impl(*rhs.pImpl_))
|
||||
{}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::
|
||||
PhysicalQuantity(PhysicalQuantity&& rhs)
|
||||
: pImpl_(std::move(rhs.pImpl_))
|
||||
{}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity&
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::operator=(const PhysicalQuantity& rhs)
|
||||
{
|
||||
this->pImpl_.reset(new Impl(*rhs.pImpl_));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity&
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::operator=(PhysicalQuantity&& rhs)
|
||||
{
|
||||
this->pImpl_ = std::move(rhs.pImpl_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity&
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::from(const UnitSystem& usys)
|
||||
{
|
||||
this->pImpl_->from(usys);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity&
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::to(const UnitSystem& usys)
|
||||
{
|
||||
this->pImpl_->to(usys);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Opm::ECLUnits::UnitSystem*
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::from() const
|
||||
{
|
||||
return this->pImpl_->from();
|
||||
}
|
||||
|
||||
const Opm::ECLUnits::UnitSystem*
|
||||
Opm::ECLUnits::Convert::PhysicalQuantity::to() const
|
||||
{
|
||||
return this->pImpl_->to();
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
|
||||
namespace {
|
||||
void rescaleVector(const double factor, std::vector<double>& x)
|
||||
{
|
||||
for (auto& xi : x) {
|
||||
xi *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
void validateUnitConventions(const std::string& name,
|
||||
const Opm::ECLUnits::UnitSystem* from,
|
||||
const Opm::ECLUnits::UnitSystem* to)
|
||||
{
|
||||
if (from == nullptr) {
|
||||
throw std::invalid_argument {
|
||||
"Cannot Perform " + name + " Value Unit Conversion "
|
||||
"Without Known 'From' Unit System Convention"
|
||||
};
|
||||
}
|
||||
|
||||
if (to == nullptr) {
|
||||
throw std::invalid_argument {
|
||||
"Cannot Perform " + name + " Value Unit Conversion "
|
||||
"Without Known 'To' Unit System Convention"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
double calculateScaleFactor(const double from, const double to)
|
||||
{
|
||||
using namespace ::Opm::unit;
|
||||
|
||||
// "return from / to", essentially.
|
||||
return convert::to(convert::from(1.0, from), to);
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::Pressure
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::Pressure::appliedTo(std::vector<double>& press) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("Pressure", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->pressure(), to->pressure());
|
||||
|
||||
rescaleVector(scaling, press);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::Viscosity
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::Viscosity::appliedTo(std::vector<double>& mu) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("Viscosity", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->viscosity(), to->viscosity());
|
||||
|
||||
rescaleVector(scaling, mu);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::GasFVF
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::GasFVF::appliedTo(std::vector<double>& Bg) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("GasFVF", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->reservoirVolume() / from->surfaceVolumeGas(),
|
||||
to ->reservoirVolume() / to ->surfaceVolumeGas());
|
||||
|
||||
rescaleVector(scaling, Bg);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::OilFVF
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::OilFVF::appliedTo(std::vector<double>& Bo) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("OilFVF", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->reservoirVolume() / from->surfaceVolumeLiquid(),
|
||||
to ->reservoirVolume() / to ->surfaceVolumeLiquid());
|
||||
|
||||
rescaleVector(scaling, Bo);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::DissolvedGasOilRatio
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::DissolvedGasOilRatio::
|
||||
appliedTo(std::vector<double>& Rs) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("DissolvedGasOilRatio", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->dissolvedGasOilRat(),
|
||||
to ->dissolvedGasOilRat());
|
||||
|
||||
rescaleVector(scaling, Rs);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// class Convert::VaporisedOilGasRatio
|
||||
// =====================================================================
|
||||
|
||||
void
|
||||
Opm::ECLUnits::Convert::VaporisedOilGasRatio::
|
||||
appliedTo(std::vector<double>& Rv) const
|
||||
{
|
||||
const auto* from = this->from();
|
||||
const auto* to = this->to();
|
||||
|
||||
validateUnitConventions("VaporisedOilGasRatio", from, to);
|
||||
|
||||
const auto scaling =
|
||||
calculateScaleFactor(from->vaporisedOilGasRat(),
|
||||
to ->vaporisedOilGasRat());
|
||||
|
||||
rescaleVector(scaling, Rv);
|
||||
}
|
@ -0,0 +1,467 @@
|
||||
/*
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_ECLPROPERTYUNITCONVERSION_HEADER_INCLUDED
|
||||
#define OPM_ECLPROPERTYUNITCONVERSION_HEADER_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class ECLRestartData;
|
||||
class ECLInitFileData;
|
||||
|
||||
namespace ECLUnits {
|
||||
|
||||
struct UnitSystem;
|
||||
|
||||
/// Construct a Unit System object corresponding to the main grid's
|
||||
/// unit convention of a Restart result set.
|
||||
///
|
||||
/// \param[in] rstrt ECL Restart data set from which to extract unit
|
||||
/// system convention (e.g., METRIC or FIELD).
|
||||
///
|
||||
/// \return Unit System object corresponding to the main grid's
|
||||
/// system convention of the currently selected restart step.
|
||||
std::unique_ptr<const UnitSystem>
|
||||
serialisedUnitConventions(const ECLRestartData& rstrt);
|
||||
|
||||
/// Construct a Unit System object corresponding to the main grid's
|
||||
/// unit convention of an INIT file result set.
|
||||
///
|
||||
/// \param[in] init ECL INIT file data set from which to extract
|
||||
/// unit system convention (e.g., METRIC or FIELD).
|
||||
///
|
||||
/// \return Unit System object corresponding to the main grid's
|
||||
/// system convention of the INIT file result set.
|
||||
std::unique_ptr<const UnitSystem>
|
||||
serialisedUnitConventions(const ECLInitFileData& init);
|
||||
|
||||
/// Construct a Unit System object corresponding to the module's
|
||||
/// internal unit system convention (strict SI).
|
||||
///
|
||||
/// \return Unit System object corresponding to the module's
|
||||
/// internal unit system convention (i.e., strict SI).
|
||||
std::unique_ptr<const UnitSystem> internalUnitConventions();
|
||||
|
||||
/// Construct a Unit System object corresponding to ECLIPSE's
|
||||
/// "METRIC" unit system convention.
|
||||
///
|
||||
/// \return Unit System object corresponding to ECLIPSE's
|
||||
/// "METRIC" unit system convention.
|
||||
std::unique_ptr<const UnitSystem> metricUnitConventions();
|
||||
|
||||
/// Construct a Unit System object corresponding to ECLIPSE's
|
||||
/// "FIELD" unit system convention.
|
||||
///
|
||||
/// \return Unit System object corresponding to ECLIPSE's
|
||||
/// "FIELD" unit system convention.
|
||||
std::unique_ptr<const UnitSystem> fieldUnitConventions();
|
||||
|
||||
/// Construct a Unit System object corresponding to ECLIPSE's
|
||||
/// "LAB" unit system convention.
|
||||
///
|
||||
/// \return Unit System object corresponding to ECLIPSE's
|
||||
/// "LAB" unit system convention.
|
||||
std::unique_ptr<const UnitSystem> labUnitConventions();
|
||||
|
||||
/// Construct a Unit System object corresponding to ECLIPSE's
|
||||
/// "PVT-M" unit system convention.
|
||||
///
|
||||
/// \return Unit System object corresponding to ECLIPSE's
|
||||
/// "PVT-M" unit system convention.
|
||||
std::unique_ptr<const UnitSystem> pvtmUnitConventions();
|
||||
|
||||
/// Facility for converting the units of measure of selected
|
||||
/// physcial quanties between user-specified systems of unit
|
||||
/// convention.
|
||||
struct Convert
|
||||
{
|
||||
/// Representation of a physical quantity
|
||||
///
|
||||
/// Base class. Resource management and operations common to
|
||||
/// all particular/specific physical quantities.
|
||||
class PhysicalQuantity
|
||||
{
|
||||
public:
|
||||
/// Default constructor.
|
||||
PhysicalQuantity();
|
||||
|
||||
/// Destructor.
|
||||
virtual ~PhysicalQuantity();
|
||||
|
||||
/// Copy constructor.
|
||||
///
|
||||
/// \param[in] rhs Existing physical quantity.
|
||||
PhysicalQuantity(const PhysicalQuantity& rhs);
|
||||
|
||||
/// Move constructor.
|
||||
///
|
||||
/// Subsumes the implementation of an existing Physical
|
||||
/// Quantity.
|
||||
///
|
||||
/// \param[in] rhs Existing physical quantity. Does not
|
||||
/// have a valid implementation when the constructor
|
||||
/// completes.
|
||||
PhysicalQuantity(PhysicalQuantity&& rhs);
|
||||
|
||||
/// Assignment operator
|
||||
///
|
||||
/// \param[in] rhs Existing Physical Quantity.
|
||||
///
|
||||
/// \return \code *this \endcode.
|
||||
PhysicalQuantity& operator=(const PhysicalQuantity& rhs);
|
||||
|
||||
/// Move assignment operator.
|
||||
///
|
||||
/// Subsumes the implementation of an existing object.
|
||||
///
|
||||
/// \param[in] rhs Existing Physical Quantity. Does not
|
||||
/// have a valid implementation when the assignment
|
||||
/// completes.
|
||||
///
|
||||
/// \return \code *this \endcode.
|
||||
PhysicalQuantity& operator=(PhysicalQuantity&& rhs);
|
||||
|
||||
/// Specify collection of units of measure of the inputs.
|
||||
///
|
||||
/// \param[in] usys Collection of units of measure of inputs.
|
||||
///
|
||||
/// \return \code *this \endcode.
|
||||
PhysicalQuantity& from(const UnitSystem& usys);
|
||||
|
||||
/// Specify collection of units of measure of the output.
|
||||
///
|
||||
/// \param[in] usys Collection of units of measure of outputs.
|
||||
///
|
||||
/// \return \code *this \endcode.
|
||||
PhysicalQuantity& to(const UnitSystem& usys);
|
||||
|
||||
/// Convert a physical quantity from its input unit of
|
||||
/// measure to its output unit of measure.
|
||||
///
|
||||
/// Must be overridden in derived classes.
|
||||
///
|
||||
/// \param[in,out] x On input, a sequence of values of a
|
||||
/// physical quantities assumed to be defined in the
|
||||
/// input unit specified through \code from(usys)
|
||||
/// \endcode. On output, the same seqeuence of values
|
||||
/// converted to the output unit of measure specified
|
||||
/// through \code to(usys) \endcode.
|
||||
virtual void appliedTo(std::vector<double>& x) const = 0;
|
||||
|
||||
protected:
|
||||
/// Retrieve input unit system.
|
||||
///
|
||||
/// Exists for the benefit of derived classes.
|
||||
///
|
||||
/// \return Input unit system. Null if not specified by
|
||||
/// caller.
|
||||
const UnitSystem* from() const;
|
||||
|
||||
/// Retrieve output unit system.
|
||||
///
|
||||
/// Exists for the benefit of derived classes.
|
||||
///
|
||||
/// \return Output unit system. Null if not specified by
|
||||
/// caller.
|
||||
const UnitSystem* to() const;
|
||||
|
||||
private:
|
||||
/// Implementation class.
|
||||
class Impl;
|
||||
|
||||
/// Pointer to implementation.
|
||||
std::unique_ptr<Impl> pImpl_;
|
||||
};
|
||||
|
||||
/// Facility for converting pressure values between
|
||||
/// user-selected units of measure.
|
||||
class Pressure : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of pressure values from its input
|
||||
/// unit of measure to its output unit of measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Convert LGR-1's oil pressure values on restart
|
||||
/// step 123 from serialised format on disk (unified
|
||||
/// restart) to internal units of measure (SI).
|
||||
/// \code
|
||||
/// const auto rstrt = ECLRestartData{ "Case.UNRST" };
|
||||
/// const auto native = serialisedUnitConventions(rstrt);
|
||||
/// const auto si = internalUnitConvention();
|
||||
///
|
||||
/// rstrt.selectReportStep(123);
|
||||
/// auto press = rstrt.keywordData<double>("PRESSURE", "LGR-1");
|
||||
/// Convert::Pressure().from(*native).to(*si).appliedTo(press);
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] press On input, a sequence of pressure
|
||||
/// values assumed to be defined in the input unit
|
||||
/// specified through \code from(usys) \endcode. On
|
||||
/// output, the same seqeuence of pressure values
|
||||
/// converted to the output unit of measure specified
|
||||
/// through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& press) const override;
|
||||
};
|
||||
|
||||
/// Facility for converting viscosity values between
|
||||
/// user-selected units of measure.
|
||||
class Viscosity : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of fluid phase viscosity values from
|
||||
/// its input unit of measure to its output unit of measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Compute the dynamic gas viscosity value in cell
|
||||
/// 27182 on restart step 10 and report it in LAB units.
|
||||
/// \code
|
||||
/// const auto rset = ResultSet("Case.EGRID");
|
||||
/// const auto init = ECLInitFileData{ rset.initFile() };
|
||||
/// const auto G = ECLGraph.load(rset.gridFile(), init);
|
||||
/// const auto rstrt = ECLRestartData{ rset.restartFile(10) };
|
||||
/// const auto si = internalUnitConvention();
|
||||
/// const auto lab = labUnitConvention();
|
||||
///
|
||||
/// rstrt.selectReportStep(10);
|
||||
/// const auto press = G.linearisedCellData<double>
|
||||
/// (rstrt, "PRESSURE", &UnitSystem::pressure);
|
||||
///
|
||||
/// const auto rv = G.linearisedCellData<double>
|
||||
/// (rstrt, "RV", &UnitSystem::vaporisedOilGasRat);
|
||||
///
|
||||
/// const auto pvtCC = ECLPvtCurveCollection(G, init);
|
||||
///
|
||||
/// auto mu = pvtCC.getDynamicProperty(RawCurve::Viscosity,
|
||||
/// ECLPhaseIndex::Vapour, 27182,
|
||||
/// std::vector<double>{ press[27182] },
|
||||
/// std::vector<double>{ rv.empty() ? 0.0 : rv[27182] });
|
||||
///
|
||||
/// Convert::Viscosity().to(*lab).from(*si).appliedTo(mu);
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] mu On input, a sequence of viscosity
|
||||
/// values assumed to be defined in the input unit
|
||||
/// specified through \code from(usys) \endcode. On
|
||||
/// output, the same seqeuence of viscosity values
|
||||
/// converted to the output unit of measure specified
|
||||
/// through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& mu) const override;
|
||||
};
|
||||
|
||||
/// Facility for converting gas phase formation volume factor
|
||||
/// values between user-selected units of measure.
|
||||
class GasFVF : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of formation volume factor values for
|
||||
/// the gas/vapour phase from its input unit of measure to
|
||||
/// its output unit of measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Compute the dynamic gas formation volume factor
|
||||
/// value in cell 57721 on restart step 314 and report it
|
||||
/// in Field units.
|
||||
/// \code
|
||||
/// const auto rset = ResultSet("Case.EGRID");
|
||||
/// const auto init = ECLInitFileData{ rset.initFile() };
|
||||
/// const auto G = ECLGraph.load(rset.gridFile(), init);
|
||||
/// const auto rstrt = ECLRestartData{ rset.restartFile(10) };
|
||||
/// const auto si = internalUnitConvention();
|
||||
/// const auto field = fieldUnitConvention();
|
||||
///
|
||||
/// rstrt.selectReportStep(314);
|
||||
/// const auto press = G.linearisedCellData<double>
|
||||
/// (rstrt, "PRESSURE", &UnitSystem::pressure);
|
||||
///
|
||||
/// const auto rv = G.linearisedCellData<double>
|
||||
/// (rstrt, "RV", &UnitSystem::vaporisedOilGasRat);
|
||||
///
|
||||
/// const auto pvtCC = ECLPvtCurveCollection(G, init);
|
||||
///
|
||||
/// auto Bg = pvtCC.getDynamicProperty(RawCurve::FVF,
|
||||
/// ECLPhaseIndex::Vapour, 57721,
|
||||
/// std::vector<double>{ press[57721] },
|
||||
/// std::vector<double>{ rv.empty() ? 0.0 : rv[57721] });
|
||||
///
|
||||
/// Convert::GasFVF().to(*field).from(*si).appliedTo(Bg);
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] Bg On input, a sequence of formation
|
||||
/// volume factor values for the gas phase assumed to be
|
||||
/// defined in the input unit specified through \code
|
||||
/// from(usys) \endcode. On output, the same seqeuence
|
||||
/// of gas FVF values converted to the output unit of
|
||||
/// measure specified through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& Bg) const override;
|
||||
};
|
||||
|
||||
/// Facility for converting oil phase formation volume factor
|
||||
/// values between user-selected units of measure.
|
||||
class OilFVF : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of formation volume factor values for
|
||||
/// the oil/liquid phase from its input unit of measure to
|
||||
/// its output unit of measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Extract the dynamic oil formation volume factor
|
||||
/// curve in cell 355,113 in native units (convention of
|
||||
/// serialised result set).
|
||||
/// \code
|
||||
/// const auto rset = ResultSet("Case.EGRID");
|
||||
/// const auto init = ECLInitFileData{ rset.initFile() };
|
||||
/// const auto G = ECLGraph.load(rset.gridFile(), init);
|
||||
/// const auto si = internalUnitConvention();
|
||||
/// const auto native = serialisedUnitConventions(init);
|
||||
///
|
||||
/// const auto pvtCC = ECLPvtCurveCollection(G, init);
|
||||
///
|
||||
/// auto BoCurves = pvtCC.getPvtCurve(RawCurve::FVF,
|
||||
/// ECLPhaseIndex::Liquid, 355113);
|
||||
///
|
||||
/// const auto cvrtPress =
|
||||
/// Convert::Pressure().to(*native).from(*si);
|
||||
/// const auto cvrtBo =
|
||||
/// Convert::OilFVF().to(*native).from(*si);
|
||||
///
|
||||
/// for (auto& curve : BoCurves) {
|
||||
/// cvrtPress.appliedTo(curve.first);
|
||||
/// cvrtBo .appliedTo(curve.second);
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] Bo On input, a sequence of formation
|
||||
/// volume factor values for the oil phase assumed to be
|
||||
/// defined in the input unit specified through \code
|
||||
/// from(usys) \endcode. On output, the same seqeuence
|
||||
/// of oil FVF values converted to the output unit of
|
||||
/// measure specified through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& Bo) const override;
|
||||
};
|
||||
|
||||
/// Facility for converting dissolved gas/oil ratio (Rs) values
|
||||
/// between user-selected units of measure.
|
||||
class DissolvedGasOilRatio : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of dissolved gas/oil ratio values
|
||||
/// from its input unit of measure to its output unit of
|
||||
/// measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Extract the saturated state curve for oil in
|
||||
/// cell 14142 in PVT-M units.
|
||||
/// \code
|
||||
/// const auto rset = ResultSet("Case.EGRID");
|
||||
/// const auto init = ECLInitFileData{ rset.initFile() };
|
||||
/// const auto G = ECLGraph.load(rset.gridFile(), init);
|
||||
/// const auto si = internalUnitConvention();
|
||||
/// const auto pvt_m = pvtmUnitConventions();
|
||||
///
|
||||
/// const auto pvtCC = ECLPvtCurveCollection(G, init);
|
||||
///
|
||||
/// const auto satState =
|
||||
/// pvtCC.getPvtCurve(RawCurve::SaturatedState,
|
||||
/// ECLPhaseIndex::Liquid, 14142);
|
||||
///
|
||||
/// Convert::DissolvedGasOilRatio().to(*pvt_m).from(*si)
|
||||
/// .appliedTo(satState.first);
|
||||
///
|
||||
/// Convert::Pressure().to(*pvt_m).from(*si)
|
||||
/// .appliedTo(satState.second);
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] Rs On input, a sequence of dissolved
|
||||
/// gas/oil ratio values assumed to be defined in the
|
||||
/// input unit specified through \code from(usys)
|
||||
/// \endcode. On output, the same seqeuence of oil Rs
|
||||
/// values converted to the output unit of measure
|
||||
/// specified through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& Rs) const override;
|
||||
};
|
||||
|
||||
/// Facility for converting vaporised oil/gas ratio (Rv) values
|
||||
/// between user-selected units of measure.
|
||||
class VaporisedOilGasRatio : public PhysicalQuantity {
|
||||
public:
|
||||
/// Convert a sequence of vaporised oil/gas ratio values
|
||||
/// from its input unit of measure to its output unit of
|
||||
/// measure.
|
||||
///
|
||||
/// Will throw an exception of type \code
|
||||
/// std::invalid_argument \endcode unless both of the input
|
||||
/// and output unit system conventions have been previously
|
||||
/// specified.
|
||||
///
|
||||
/// Example: Extract the saturated state curve for gas in
|
||||
/// cell 161803 in Metric units.
|
||||
/// \code
|
||||
/// const auto rset = ResultSet("Case.EGRID");
|
||||
/// const auto init = ECLInitFileData{ rset.initFile() };
|
||||
/// const auto G = ECLGraph.load(rset.gridFile(), init);
|
||||
/// const auto si = internalUnitConvention();
|
||||
/// const auto metric = metricUnitConventions();
|
||||
///
|
||||
/// const auto pvtCC = ECLPvtCurveCollection(G, init);
|
||||
///
|
||||
/// const auto satState =
|
||||
/// pvtCC.getPvtCurve(RawCurve::SaturatedState,
|
||||
/// ECLPhaseIndex::Vapour, 161803);
|
||||
///
|
||||
/// Convert::Pressure().to(*metric).from(*si)
|
||||
/// .appliedTo(satState.first);
|
||||
///
|
||||
/// Convert::VaporisedOilGasRatio().to(*metric).from(*si)
|
||||
/// .appliedTo(satState.second);
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in,out] Rv On input, a sequence of vapourised
|
||||
/// oil/gas ratio values assumed to be defined in the
|
||||
/// input unit specified through \code from(usys)
|
||||
/// \endcode. On output, the same seqeuence of gas Rv
|
||||
/// values converted to the output unit of measure
|
||||
/// specified through \code to(usys) \endcode.
|
||||
void appliedTo(std::vector<double>& Rv) const override;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace ECLUnits
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_ECLPROPERTYUNITCONVERSION_HEADER_INCLUDED
|
@ -265,6 +265,11 @@ Opm::ECLPVT::PVDx::viscosity(const std::vector<double>& p) const
|
||||
Opm::FlowDiagnostics::Graph
|
||||
Opm::ECLPVT::PVDx::getPvtCurve(const RawCurve curve) const
|
||||
{
|
||||
if (curve == RawCurve::SaturatedState) {
|
||||
// Not applicable to dry gas or dead oil. Return empty.
|
||||
return FlowDiagnostics::Graph{};
|
||||
}
|
||||
|
||||
return extractRawPVTCurve(this->interp_, curve);
|
||||
}
|
||||
|
||||
|
@ -669,28 +669,11 @@ namespace Opm { namespace ECLPVT {
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
getPvtCurve(const RawCurve curve) const
|
||||
{
|
||||
auto ret = std::vector<FlowDiagnostics::Graph>{};
|
||||
ret.reserve(this->propInterp_.size());
|
||||
|
||||
for (const auto& interp : this->propInterp_) {
|
||||
ret.push_back(extractRawPVTCurve(interp, curve));
|
||||
if (curve == RawCurve::SaturatedState) {
|
||||
return this->saturatedStateCurve();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<double> getSaturatedPoints() const
|
||||
{
|
||||
auto y = std::vector<double>{};
|
||||
y.reserve(this->propInterp_.size());
|
||||
|
||||
for (const auto& interp : this->propInterp_) {
|
||||
const auto& yi = interp.independentVariable();
|
||||
|
||||
y.push_back(yi[0]);
|
||||
}
|
||||
|
||||
return y;
|
||||
return this->mainPvtCurve(curve);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -844,6 +827,37 @@ namespace Opm { namespace ECLPVT {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
mainPvtCurve(const RawCurve curve) const
|
||||
{
|
||||
auto ret = std::vector<FlowDiagnostics::Graph>{};
|
||||
ret.reserve(this->propInterp_.size());
|
||||
|
||||
for (const auto& interp : this->propInterp_) {
|
||||
ret.push_back(extractRawPVTCurve(interp, curve));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<FlowDiagnostics::Graph> saturatedStateCurve() const
|
||||
{
|
||||
auto y = std::vector<double>{};
|
||||
y.reserve(this->propInterp_.size());
|
||||
|
||||
for (const auto& interp : this->propInterp_) {
|
||||
const auto& yi = interp.independentVariable();
|
||||
|
||||
y.push_back(yi[0]);
|
||||
}
|
||||
|
||||
return {
|
||||
FlowDiagnostics::Graph {
|
||||
this->key_, std::move(y)
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Extract component mass density at surface conditions.
|
||||
|
@ -19,8 +19,10 @@
|
||||
|
||||
#include <opm/utility/ECLPvtCurveCollection.hpp>
|
||||
|
||||
#include <opm/utility/ECLPropertyUnitConversion.hpp>
|
||||
#include <opm/utility/ECLResultData.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
@ -42,61 +44,252 @@ namespace {
|
||||
return pvtnum;
|
||||
}
|
||||
|
||||
std::unique_ptr<const Opm::ECLUnits::UnitSystem>
|
||||
createUnitSystem(const ::Opm::ECLInitFileData& init)
|
||||
{
|
||||
const auto& ih = init.keywordData<int>(INTEHEAD_KW);
|
||||
|
||||
return ::Opm::ECLUnits::createUnitSystem(ih[ INTEHEAD_UNIT_INDEX ]);
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph> emptyFDGraph()
|
||||
{
|
||||
return { Opm::FlowDiagnostics::Graph{} };
|
||||
}
|
||||
|
||||
template <class PvtPtr>
|
||||
template <class PVTInterp>
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
rawPvtCurve(PvtPtr& pvt, // ref to shared_ptr<>
|
||||
rawPvtCurve(const PVTInterp* pvt,
|
||||
const Opm::ECLPVT::RawCurve curve,
|
||||
const int regID,
|
||||
const Opm::ECLUnits::UnitSystem& usys)
|
||||
const int regID)
|
||||
{
|
||||
if (pvt != nullptr) {
|
||||
return pvt->getPvtCurve(curve, regID, usys);
|
||||
}
|
||||
|
||||
if (pvt == nullptr) {
|
||||
// Result set does not provide requisite tabulated properties.
|
||||
// Return empty.
|
||||
return emptyFDGraph();
|
||||
}
|
||||
|
||||
return pvt->getPvtCurve(curve, regID);
|
||||
}
|
||||
|
||||
template <class PVTInterp, class Pressure, class MixRatio>
|
||||
std::vector<double>
|
||||
formationVolumeFactor(const PVTInterp* pvt,
|
||||
const int regID,
|
||||
const Pressure& press,
|
||||
const MixRatio& R)
|
||||
{
|
||||
assert (pvt != nullptr);
|
||||
|
||||
return pvt->formationVolumeFactor(regID, R, press);
|
||||
}
|
||||
|
||||
template <class PVTInterp, class Pressure, class MixRatio>
|
||||
std::vector<double>
|
||||
viscosity(const PVTInterp* pvt,
|
||||
const int regID,
|
||||
const Pressure& press,
|
||||
const MixRatio& R)
|
||||
{
|
||||
assert (pvt != nullptr);
|
||||
|
||||
return pvt->viscosity(regID, R, press);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
gasProperty(const Opm::ECLPVT::Gas* pvt,
|
||||
const Opm::ECLPVT::RawCurve property,
|
||||
const int regID,
|
||||
const std::vector<double>& Pg,
|
||||
const std::vector<double>& Rv)
|
||||
{
|
||||
if (pvt == nullptr) {
|
||||
// No such property interpolant. Return empty.
|
||||
return {};
|
||||
}
|
||||
|
||||
assert ((property == Opm::ECLPVT::RawCurve::FVF) ||
|
||||
(property == Opm::ECLPVT::RawCurve::Viscosity));
|
||||
|
||||
const auto pg = Opm::ECLPVT::Gas::GasPressure { Pg };
|
||||
auto rv = Opm::ECLPVT::Gas::VaporizedOil{ Rv };
|
||||
if (rv.data.empty()) {
|
||||
rv.data.assign(pg.data.size(), 0.0);
|
||||
}
|
||||
|
||||
if (property == Opm::ECLPVT::RawCurve::FVF) {
|
||||
return formationVolumeFactor(pvt, regID, pg, rv);
|
||||
}
|
||||
|
||||
return viscosity(pvt, regID, pg, rv);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
oilProperty(const Opm::ECLPVT::Oil* pvt,
|
||||
const Opm::ECLPVT::RawCurve property,
|
||||
const int regID,
|
||||
const std::vector<double>& Po,
|
||||
const std::vector<double>& Rs)
|
||||
{
|
||||
if (pvt == nullptr) {
|
||||
// No such property interpolant. Return empty.
|
||||
return {};
|
||||
}
|
||||
|
||||
assert ((property == Opm::ECLPVT::RawCurve::FVF) ||
|
||||
(property == Opm::ECLPVT::RawCurve::Viscosity));
|
||||
|
||||
const auto po = Opm::ECLPVT::Oil::OilPressure { Po };
|
||||
auto rs = Opm::ECLPVT::Oil::DissolvedGas{ Rs };
|
||||
if (rs.data.empty()) {
|
||||
rs.data.assign(po.data.size(), 0.0);
|
||||
}
|
||||
|
||||
if (property == Opm::ECLPVT::RawCurve::FVF) {
|
||||
return formationVolumeFactor(pvt, regID, po, rs);
|
||||
}
|
||||
|
||||
return viscosity(pvt, regID, po, rs);
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
convertCurve(std::vector<Opm::FlowDiagnostics::Graph>&& curves,
|
||||
const Opm::ECLUnits::Convert::PhysicalQuantity& cvrt_x,
|
||||
const Opm::ECLUnits::Convert::PhysicalQuantity& cvrt_y)
|
||||
{
|
||||
for (auto& curve : curves) {
|
||||
cvrt_x.appliedTo(curve.first);
|
||||
cvrt_y.appliedTo(curve.second);
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
convertFvfCurve(std::vector<Opm::FlowDiagnostics::Graph>&& curve,
|
||||
const Opm::ECLPhaseIndex phase,
|
||||
const Opm::ECLUnits::UnitSystem& usysFrom,
|
||||
const Opm::ECLUnits::UnitSystem& usysTo)
|
||||
{
|
||||
assert ((phase == Opm::ECLPhaseIndex::Liquid) ||
|
||||
(phase == Opm::ECLPhaseIndex::Vapour));
|
||||
|
||||
if (phase == Opm::ECLPhaseIndex::Liquid) {
|
||||
// Oil FVF. First column is pressure, second column is Bo.
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::Pressure()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
const auto& cvrt_y = Opm::ECLUnits::Convert::OilFVF()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
// Gas FVF. Need to distinguish miscible from immiscible cases. In
|
||||
// the former, the first column is Rv (vapourised oil/gas ratio) and
|
||||
// in the second case the first column is the gas pressure.
|
||||
//
|
||||
// Immiscible case identified by curve.size() <= 1.
|
||||
|
||||
const auto& cvrt_y = Opm::ECLUnits::Convert::GasFVF()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
if (curve.size() <= 1) {
|
||||
// Immiscible Gas FVF. First column is Pg.
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::Pressure()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
// Miscible Gas FVF. First column is Rv.
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::VaporisedOilGasRatio()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
convertViscosityCurve(std::vector<Opm::FlowDiagnostics::Graph>&& curve,
|
||||
const Opm::ECLPhaseIndex phase,
|
||||
const Opm::ECLUnits::UnitSystem& usysFrom,
|
||||
const Opm::ECLUnits::UnitSystem& usysTo)
|
||||
{
|
||||
assert ((phase == Opm::ECLPhaseIndex::Liquid) ||
|
||||
(phase == Opm::ECLPhaseIndex::Vapour));
|
||||
|
||||
// This is the viscosity curve. Second column is always viscosity
|
||||
// irrespective of phase or miscible/immiscible fluids.
|
||||
const auto& cvrt_y = Opm::ECLUnits::Convert::Viscosity()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
if ((phase == Opm::ECLPhaseIndex::Liquid) || (curve.size() <= 1)) {
|
||||
// Graph is oil viscosity or immiscible gas viscosity. First
|
||||
// column is pressure.
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::Pressure()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
// Miscible Gas viscosity. First column is Rv (vapourised oil/gas
|
||||
// ratio).
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::VaporisedOilGasRatio()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
convertSatStateCurve(std::vector<Opm::FlowDiagnostics::Graph>&& curve,
|
||||
const Opm::ECLPhaseIndex phase,
|
||||
const Opm::ECLUnits::UnitSystem& usysFrom,
|
||||
const Opm::ECLUnits::UnitSystem& usysTo)
|
||||
{
|
||||
assert ((phase == Opm::ECLPhaseIndex::Liquid) ||
|
||||
(phase == Opm::ECLPhaseIndex::Vapour));
|
||||
|
||||
// First column is pressure (Po or Pg).
|
||||
const auto& cvrt_x = Opm::ECLUnits::Convert::Pressure()
|
||||
.from(usysFrom).to(usysTo);
|
||||
|
||||
// Second column is Rs or Rv depending on 'phase'.
|
||||
if (phase == Opm::ECLPhaseIndex::Liquid) {
|
||||
// Saturated state curve for miscible oil. Second column is Rs
|
||||
// (dissolved gas/oil ratio).
|
||||
const auto& cvrt_y = Opm::ECLUnits::Convert::
|
||||
DissolvedGasOilRatio().from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
|
||||
// Saturated state curve for miscible gas. Second column is Rv
|
||||
// (vapourised oil/gas ratio).
|
||||
const auto& cvrt_y = Opm::ECLUnits::Convert::
|
||||
VaporisedOilGasRatio().from(usysFrom).to(usysTo);
|
||||
|
||||
return convertCurve(std::move(curve), cvrt_x, cvrt_y);
|
||||
}
|
||||
}
|
||||
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
ECLPvtCurveCollection(const ECLGraph& G,
|
||||
const ECLInitFileData& init)
|
||||
: pvtnum_(pvtnumVector(G, init))
|
||||
, gas_ (CreateGasPVTInterpolant::fromECLOutput(init)) // u_p<> -> s_p<>
|
||||
, oil_ (CreateOilPVTInterpolant::fromECLOutput(init)) // u_p<> -> s_p<>
|
||||
, usys_ (createUnitSystem(init)) // u_p<> -> s_p<>
|
||||
: pvtnum_ (pvtnumVector(G, init))
|
||||
, gas_ (CreateGasPVTInterpolant::fromECLOutput(init))
|
||||
, oil_ (CreateOilPVTInterpolant::fromECLOutput(init))
|
||||
, usys_native_ (ECLUnits::serialisedUnitConventions(init))
|
||||
, usys_internal_(ECLUnits::internalUnitConventions())
|
||||
{}
|
||||
|
||||
void
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
setOutputUnits(std::unique_ptr<const ECLUnits::UnitSystem> usys)
|
||||
{
|
||||
this->usys_output_ = std::move(usys);
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
getPvtCurve(const RawCurve curve,
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell) const
|
||||
{
|
||||
if (phase == ECLPhaseIndex::Aqua) {
|
||||
// Not supported at this time.
|
||||
// Return empty.
|
||||
return emptyFDGraph();
|
||||
}
|
||||
|
||||
if (static_cast<decltype(this->pvtnum_.size())>(activeCell)
|
||||
>= this->pvtnum_.size())
|
||||
{
|
||||
// Active cell index out of bounds. Return empty.
|
||||
if (! this->isValidRequest(phase, activeCell)) {
|
||||
// Not a supported phase or cell index out of bounds. Not a valid
|
||||
// request so return empty.
|
||||
return emptyFDGraph();
|
||||
}
|
||||
|
||||
@ -106,9 +299,180 @@ getPvtCurve(const RawCurve curve,
|
||||
|
||||
if (phase == ECLPhaseIndex::Liquid) {
|
||||
// Caller requests oil properties.
|
||||
return rawPvtCurve(this->oil_, curve, regID, *this->usys_);
|
||||
return this->convertToOutputUnits(
|
||||
rawPvtCurve(this->oil_.get(), curve, regID), curve, phase);
|
||||
}
|
||||
|
||||
// Call requests gas properties.
|
||||
return rawPvtCurve(this->gas_, curve, regID, *this->usys_);
|
||||
// Caller requests gas properties.
|
||||
assert ((phase == ECLPhaseIndex::Vapour) &&
|
||||
"Internal Logic Error Identifying Supported Phases");
|
||||
|
||||
return this->convertToOutputUnits(
|
||||
rawPvtCurve(this->gas_.get(), curve, regID), curve, phase);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
getDynamicPropertySI(const RawCurve property,
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell,
|
||||
const std::vector<double>& phasePress,
|
||||
const std::vector<double>& mixRatio) const
|
||||
{
|
||||
if (! this->isValidRequest(phase, activeCell) ||
|
||||
(property == RawCurve::SaturatedState))
|
||||
{
|
||||
// Not a supported phase, cell index out of bounds, or caller
|
||||
// requests dynamically evaluating the saturated state curve. Not a
|
||||
// valid request so return empty.
|
||||
return {};
|
||||
}
|
||||
|
||||
// PVTNUM is traditional one-based region identifier. Subtract one to
|
||||
// form valid index into std::vector<>s.
|
||||
const auto regID = this->pvtnum_[activeCell] - 1;
|
||||
|
||||
if (phase == ECLPhaseIndex::Liquid) {
|
||||
// Caller requests oil properties.
|
||||
return oilProperty(this->oil_.get(), property,
|
||||
regID, phasePress, mixRatio);
|
||||
}
|
||||
|
||||
// Caller requests gas properties.
|
||||
assert ((phase == ECLPhaseIndex::Vapour) &&
|
||||
"Internal Logic Error Identifying Supported Phases");
|
||||
|
||||
return gasProperty(this->gas_.get(), property,
|
||||
regID, phasePress, mixRatio);
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
getDynamicPropertyNative(const RawCurve property,
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell,
|
||||
std::vector<double> phasePress,
|
||||
std::vector<double> mixRatio) const
|
||||
{
|
||||
if (! this->isValidRequest(phase, activeCell) ||
|
||||
(property == RawCurve::SaturatedState))
|
||||
{
|
||||
// Not a supported phase, cell index out of bounds, or caller
|
||||
// requests dynamically evaluating the saturated state curve. Not a
|
||||
// valid request so return empty.
|
||||
return {};
|
||||
}
|
||||
|
||||
assert (this->usys_native_ != nullptr);
|
||||
assert (this->usys_internal_ != nullptr);
|
||||
|
||||
// 1) Convert inputs from native to internal (SI) units of measurement.
|
||||
::Opm::ECLUnits::Convert::Pressure()
|
||||
.from(*this->usys_native_)
|
||||
.to (*this->usys_internal_).appliedTo(phasePress);
|
||||
|
||||
if (phase == ECLPhaseIndex::Liquid) {
|
||||
::Opm::ECLUnits::Convert::DissolvedGasOilRatio()
|
||||
.from(*this->usys_native_)
|
||||
.to (*this->usys_internal_).appliedTo(mixRatio);
|
||||
}
|
||||
else {
|
||||
assert (phase == ECLPhaseIndex::Vapour);
|
||||
|
||||
::Opm::ECLUnits::Convert::VaporisedOilGasRatio()
|
||||
.from(*this->usys_native_)
|
||||
.to (*this->usys_internal_).appliedTo(mixRatio);
|
||||
}
|
||||
|
||||
// 2) Evaluate requested property in strict SI units.
|
||||
auto prop = this->getDynamicPropertySI(property, phase, activeCell,
|
||||
phasePress, mixRatio);
|
||||
|
||||
// 3) Convert property values to user's requested system of units.
|
||||
|
||||
if (this->usys_output_ == nullptr) {
|
||||
// No user-defined system of units for outputs. Use PropertySI()
|
||||
// directly.
|
||||
return prop;
|
||||
}
|
||||
|
||||
// Caller has defined a particular system of units for outputs. Convert
|
||||
// 'prop' accordingly.
|
||||
if (property == RawCurve::Viscosity) {
|
||||
// The 'prop' values represent viscosities.
|
||||
::Opm::ECLUnits::Convert::Viscosity()
|
||||
.from(*this->usys_internal_)
|
||||
.to (*this->usys_output_).appliedTo(prop);
|
||||
}
|
||||
else {
|
||||
assert (property == RawCurve::FVF);
|
||||
|
||||
if (phase == ECLPhaseIndex::Vapour) {
|
||||
// The 'prop' values represent Bg.
|
||||
::Opm::ECLUnits::Convert::GasFVF()
|
||||
.from(*this->usys_internal_)
|
||||
.to (*this->usys_output_).appliedTo(prop);
|
||||
}
|
||||
else {
|
||||
assert (phase == ECLPhaseIndex::Liquid);
|
||||
|
||||
::Opm::ECLUnits::Convert::OilFVF()
|
||||
.from(*this->usys_internal_)
|
||||
.to (*this->usys_output_).appliedTo(prop);
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
bool
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
isValidRequest(const ECLPhaseIndex phase,
|
||||
const int activeCell) const
|
||||
{
|
||||
if (! ((phase == ECLPhaseIndex::Liquid) ||
|
||||
(phase == ECLPhaseIndex::Vapour)))
|
||||
{
|
||||
// We support "liquid" and "vapour" phase (oil/gas) properties only.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if cell index is within bounds.
|
||||
return static_cast<decltype(this->pvtnum_.size())>(activeCell)
|
||||
< this->pvtnum_.size();
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||
convertToOutputUnits(std::vector<FlowDiagnostics::Graph>&& graph,
|
||||
const RawCurve curve,
|
||||
const ECLPhaseIndex phase) const
|
||||
{
|
||||
if (this->usys_output_ == nullptr) {
|
||||
// No defined system of units for outputs. Return unconverted (SI).
|
||||
return graph;
|
||||
}
|
||||
|
||||
assert ((phase == ECLPhaseIndex::Liquid) ||
|
||||
(phase == ECLPhaseIndex::Vapour));
|
||||
|
||||
if (curve == RawCurve::FVF) {
|
||||
return convertFvfCurve(std::move(graph), phase,
|
||||
*this->usys_internal_, // from
|
||||
*this->usys_output_); // to
|
||||
}
|
||||
|
||||
if (curve == RawCurve::Viscosity) {
|
||||
return convertViscosityCurve(std::move(graph), phase,
|
||||
*this->usys_internal_, // from
|
||||
*this->usys_output_); // to
|
||||
}
|
||||
|
||||
if (curve == RawCurve::SaturatedState) {
|
||||
return convertSatStateCurve(std::move(graph), phase,
|
||||
*this->usys_internal_, // from
|
||||
*this->usys_output_); // to
|
||||
}
|
||||
|
||||
throw std::invalid_argument { "Internal Logic Error" };
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <opm/utility/ECLGraph.hpp>
|
||||
#include <opm/utility/ECLPhaseIndex.hpp>
|
||||
#include <opm/utility/ECLPropertyUnitConversion.hpp>
|
||||
#include <opm/utility/ECLPvtCommon.hpp>
|
||||
#include <opm/utility/ECLPvtGas.hpp>
|
||||
#include <opm/utility/ECLPvtOil.hpp>
|
||||
@ -58,6 +59,20 @@ namespace Opm { namespace ECLPVT {
|
||||
ECLPvtCurveCollection(const ECLGraph& G,
|
||||
const ECLInitFileData& init);
|
||||
|
||||
/// Define a collection of units of measure for output purposes.
|
||||
///
|
||||
/// PVT property curves will be reported in the appropriate units of
|
||||
/// this system. If this function is never called (or called with
|
||||
/// null pointer), then the output units are implicitly set to the
|
||||
/// flow-diagnostics module's internal units of measurement (meaning
|
||||
/// all properties and curves will be reported in strict SI units).
|
||||
///
|
||||
/// \param[in] usys Collection of units of measure for output
|
||||
/// purposes. Typically the return value from one of the \code
|
||||
/// *UnitConvention() \endcode functions of the \code ECLUnits
|
||||
/// \endcode namespace.
|
||||
void setOutputUnits(std::unique_ptr<const ECLUnits::UnitSystem> usys);
|
||||
|
||||
/// Retrieve 2D graph representation of Phase PVT property function
|
||||
/// in a specific active cell.
|
||||
///
|
||||
@ -66,14 +81,16 @@ namespace Opm { namespace ECLPVT {
|
||||
/// \param[in] phase Phase for which to compute extract graph
|
||||
/// representation of PVT property function.
|
||||
///
|
||||
/// \param[in] activeCell Index of particular active cell in model..
|
||||
/// \param[in] activeCell Index of particular active cell in model.
|
||||
///
|
||||
/// \return Collection of 2D graphs for PVT property curve
|
||||
/// identified by requests represented by \p curve, \p phase and
|
||||
/// \p activeCell. One curve (vector element) for each tabulated
|
||||
/// node of the primary look-up key. Single curve (i.e., a
|
||||
/// single element vector) in the case of dry gas (no vaporised
|
||||
/// oil) or dead oil (no dissolved gas).
|
||||
/// oil) or dead oil (no dissolved gas). Return values provided
|
||||
/// in the system of units specified by setOutputUnits(). Strict
|
||||
/// SI if no output units have been defined.
|
||||
///
|
||||
/// No curves for water or dead oil with constant compressibility
|
||||
/// (i.e., keyword 'PVCDO' in the input deck).
|
||||
@ -91,6 +108,110 @@ namespace Opm { namespace ECLPVT {
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell) const;
|
||||
|
||||
/// Compute a single dynamic property in a single active cell for a
|
||||
/// collection of cell states.
|
||||
///
|
||||
/// Note: Phase property inputs (phase pressure and mixing ratios)
|
||||
/// must be in strict SI units of measure (Pascal and sm^3/sm^3,
|
||||
/// respectively).
|
||||
///
|
||||
/// \param[in] property Named property. Must be one of \code
|
||||
/// RawCurve::FVF \endcode or \code RawCurve::Viscosity \endcode.
|
||||
/// All other values return an empty result.
|
||||
///
|
||||
/// \param[in] phase Phase for which to compute the property value.
|
||||
/// Must be \code ECLPhaseIndex::Vapour \endcode or \code
|
||||
/// ECLPhaseIndex::Liquid \endcode. All other values return an
|
||||
/// empty result.
|
||||
///
|
||||
/// \param[in] activeCell Index of particular active cell in model.
|
||||
///
|
||||
/// \param[in] phasePress Sequence of phase pressure values
|
||||
/// pertaining to \p activeCell. Could, for instance, be the
|
||||
/// entire time-series of oil pressure values in that cell.
|
||||
///
|
||||
/// \param[in] mixRatio Sequence of phase mixing ratio values
|
||||
/// pertaining to \p activeCell. Could, for instance, be the
|
||||
/// entire time-series of dissolved gas/oil ratio values in that
|
||||
/// cell. Must be empty or match the size of \p phasePress. If
|
||||
/// empty, treated as \code
|
||||
/// std::vector<double>(phasePress.size(), 0.0) \endcode which is
|
||||
/// typically appropriate only for dry gas or dead oil cases.
|
||||
///
|
||||
/// \return Sequence of dynamic property values corresponding to the
|
||||
/// requested property name of the identified phase in the
|
||||
/// particular active cell. Empty for invalid requests, number
|
||||
/// of elements equal to \code phasePress.size() \endcode
|
||||
/// otherwise. Return values are in strict SI units of
|
||||
/// measure--i.e., rm^3/sm^3 for the formation volume factors and
|
||||
/// Pascal seconds for the viscosities.
|
||||
std::vector<double>
|
||||
getDynamicPropertySI(const RawCurve property,
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell,
|
||||
const std::vector<double>& phasePress,
|
||||
const std::vector<double>& mixRatio
|
||||
= std::vector<double>()) const;
|
||||
|
||||
/// Compute a single dynamic property in a single active cell for a
|
||||
/// collection of cell states.
|
||||
///
|
||||
/// This interface is intended for direct calculation based on raw
|
||||
/// (unconverted) data vectors from an ECL result set.
|
||||
/// Consequently, phase property inputs (phase pressure and mixing
|
||||
/// ratios) must be in the result set's native/serialised collection
|
||||
/// of units of measure (e.g., pressures in Atmospheres and mixing
|
||||
/// ratios in scm^3/scm^3 for the "LAB" system of units).
|
||||
///
|
||||
/// \param[in] property Named property. Must be one of \code
|
||||
/// RawCurve::FVF \endcode or \code RawCurve::Viscosity \endcode.
|
||||
/// All other values return an empty result.
|
||||
///
|
||||
/// \param[in] phase Phase for which to compute the property value.
|
||||
/// Must be \code ECLPhaseIndex::Vapour \endcode or \code
|
||||
/// ECLPhaseIndex::Liquid \endcode. All other values return an
|
||||
/// empty result.
|
||||
///
|
||||
/// \param[in] activeCell Index of particular active cell in model.
|
||||
///
|
||||
/// \param[in] phasePress Sequence of phase pressure values
|
||||
/// pertaining to \p activeCell. Could, for instance, be the
|
||||
/// entire time-series of oil pressure values in that cell. Must
|
||||
/// be in the serialised system of units (i.e., Bars for METRIC,
|
||||
/// Psi for FIELD, and Atm for LAB and PVT-M).
|
||||
///
|
||||
/// \param[in] mixRatio Sequence of phase mixing ratio values
|
||||
/// pertaining to \p activeCell. Could, for instance, be the
|
||||
/// entire time-series of dissolved gas/oil ratio values in that
|
||||
/// cell. Must be empty or match the size of \p phasePress. If
|
||||
/// empty, treated as \code
|
||||
/// std::vector<double>(phasePress.size(), 0.0) \endcode which is
|
||||
/// typically appropriate only for dry gas or dead oil cases.
|
||||
///
|
||||
/// Must be in the serialised system of units. In other words
|
||||
/// when the \p mixRatio represents the dissolved gas/oil ratio
|
||||
/// (Rs), then the input must be given in sm^3/sm^3 for METRIC,
|
||||
/// Mscf/stb for FIELD, scm^3/scm^3 for LAB and sm^3/sm^3 for
|
||||
/// PVT-M. Similarly, when the \p mixRatio represents the
|
||||
/// vapourised oil/gas ratio (Rv), then the input must be given
|
||||
/// in sm^3/sm^3 for METRIC, stb/Mscf for FIELD, scm^3/scm^3 for
|
||||
/// LAB and sm^3/sm^3 for PVT-M).
|
||||
///
|
||||
/// \return Sequence of dynamic property values corresponding to the
|
||||
/// requested property name of the identified phase in the
|
||||
/// particular active cell. Empty for invalid requests, number
|
||||
/// of elements equal to \code phasePress.size() \endcode
|
||||
/// otherwise. Return values provided in the system of units
|
||||
/// specified by setOutputUnits(). Strict SI if no output units
|
||||
/// have been defined.
|
||||
std::vector<double>
|
||||
getDynamicPropertyNative(const RawCurve property,
|
||||
const ECLPhaseIndex phase,
|
||||
const int activeCell,
|
||||
std::vector<double> phasePress, // Mutable copy
|
||||
std::vector<double> mixRatio // Mutable copy
|
||||
= std::vector<double>()) const;
|
||||
|
||||
private:
|
||||
/// Forward map: Cell -> PVT Region ID
|
||||
std::vector<int> pvtnum_;
|
||||
@ -101,8 +222,44 @@ namespace Opm { namespace ECLPVT {
|
||||
/// Oil PVT property evaluator.
|
||||
std::shared_ptr<Oil> oil_;
|
||||
|
||||
/// Unit handling (SI -> result-set convention)
|
||||
std::shared_ptr<const ECLUnits::UnitSystem> usys_;
|
||||
/// Native unit system of INIT file. Used in the implementation of
|
||||
/// member function getDynamicPropertyNative().
|
||||
std::shared_ptr<const ECLUnits::UnitSystem> usys_native_;
|
||||
|
||||
/// Explicit representation of internal system of units. Strict SI.
|
||||
/// Used in getDynamicPropertyNative().
|
||||
std::shared_ptr<const ECLUnits::UnitSystem> usys_internal_;
|
||||
|
||||
/// User-specified system of units for output of properties. Used
|
||||
/// by getPvtCurve() and getDynamicPropertyNative().
|
||||
std::shared_ptr<const ECLUnits::UnitSystem> usys_output_{nullptr};
|
||||
|
||||
/// Determine if a particular request can be met by the internal
|
||||
/// implementation.
|
||||
///
|
||||
/// \param[in] phase Phase for which to compute a property.
|
||||
///
|
||||
/// \param[in] activeCell Index of particular active cell in model.
|
||||
///
|
||||
/// \return True if \p phase is supported and \p activeCell is
|
||||
/// within range of the currently defined model. False otherwise.
|
||||
bool isValidRequest(const ECLPhaseIndex phase,
|
||||
const int activeCell) const;
|
||||
|
||||
/// Convert a sequence of 2D graphs to user-defined system of units.
|
||||
///
|
||||
/// \param[in] graph Sequence of 2D graphs corresponding to a
|
||||
/// particular curve request.
|
||||
///
|
||||
/// \param[in] property Named property.
|
||||
///
|
||||
/// \param[in] phase Phase for which to compute the property curve.
|
||||
/// Must be \code ECLPhaseIndex::Vapour \endcode or \code
|
||||
/// ECLPhaseIndex::Liquid \endcode.
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
convertToOutputUnits(std::vector<FlowDiagnostics::Graph>&& graph,
|
||||
const RawCurve curve,
|
||||
const ECLPhaseIndex phase) const;
|
||||
};
|
||||
|
||||
}} // Opm::ECLPVT
|
||||
|
@ -99,8 +99,7 @@ public:
|
||||
const std::vector<double>& pg) const = 0;
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const = 0;
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const = 0;
|
||||
|
||||
virtual std::unique_ptr<PVxGBase> clone() const = 0;
|
||||
};
|
||||
@ -135,30 +134,9 @@ public:
|
||||
}
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||
{
|
||||
if (curve == Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||
// Not applicable to dry gas. Return empty.
|
||||
return { Opm::FlowDiagnostics::Graph{} };
|
||||
}
|
||||
|
||||
auto pvtcurve = this->interpolant_.getPvtCurve(curve);
|
||||
|
||||
const auto x_unit = usys.pressure();
|
||||
const auto y_unit = (curve == ::Opm::ECLPVT::RawCurve::FVF)
|
||||
? (usys.reservoirVolume() / usys.surfaceVolumeGas())
|
||||
: usys.viscosity();
|
||||
|
||||
auto& x = pvtcurve.first;
|
||||
auto& y = pvtcurve.second;
|
||||
|
||||
for (auto n = x.size(), i = 0*n; i < n; ++i) {
|
||||
x[i] = ::Opm::unit::convert::to(x[i], x_unit);
|
||||
y[i] = ::Opm::unit::convert::to(y[i], y_unit);
|
||||
}
|
||||
|
||||
return { std::move(pvtcurve) };
|
||||
return { this->interpolant_.getPvtCurve(curve) };
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<PVxGBase> clone() const override
|
||||
@ -183,8 +161,7 @@ public:
|
||||
|
||||
WetGas(std::vector<double> key,
|
||||
std::vector<SubtableInterpolant> propInterp)
|
||||
: key_ (key) // Copy
|
||||
, interp_(std::move(key), std::move(propInterp))
|
||||
: interp_(std::move(key), std::move(propInterp))
|
||||
{}
|
||||
|
||||
virtual std::vector<double>
|
||||
@ -214,14 +191,9 @@ public:
|
||||
}
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||
{
|
||||
if (curve == ::Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||
return this->saturatedStateCurve(usys);
|
||||
}
|
||||
|
||||
return this->mainPvtCurve(curve, usys);
|
||||
return this->interp_.getPvtCurve(curve);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<PVxGBase> clone() const override
|
||||
@ -232,68 +204,9 @@ public:
|
||||
private:
|
||||
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
||||
|
||||
std::vector<double> key_;
|
||||
TableInterpolant interp_;
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
mainPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const;
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
saturatedStateCurve(const Opm::ECLUnits::UnitSystem& usys) const;
|
||||
};
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
WetGas::mainPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const
|
||||
{
|
||||
auto curves = this->interp_.getPvtCurve(curve);
|
||||
|
||||
const auto x_unit = usys.vaporisedOilGasRat();
|
||||
const auto y_unit = (curve == ::Opm::ECLPVT::RawCurve::FVF)
|
||||
? (usys.reservoirVolume() / usys.surfaceVolumeGas())
|
||||
: usys.viscosity();
|
||||
|
||||
for (auto& crv : curves) {
|
||||
auto& x = crv.first;
|
||||
auto& y = crv.second;
|
||||
|
||||
for (auto n = x.size(), i = 0*n; i < n; ++i) {
|
||||
x[i] = ::Opm::unit::convert::to(x[i], x_unit);
|
||||
y[i] = ::Opm::unit::convert::to(y[i], y_unit);
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
WetGas::saturatedStateCurve(const Opm::ECLUnits::UnitSystem& usys) const
|
||||
{
|
||||
const auto key_unit = usys.pressure();
|
||||
const auto rv_unit = usys.vaporisedOilGasRat();
|
||||
|
||||
auto rv = this->interp_.getSaturatedPoints();
|
||||
auto p = this->key_;
|
||||
|
||||
if (rv.size() != p.size()) {
|
||||
throw std::invalid_argument {
|
||||
"Inconsistent table sizes of saturated gas function (RvSat(p))"
|
||||
};
|
||||
}
|
||||
|
||||
for (auto n = rv.size(), i = 0*n; i < n; ++i) {
|
||||
p [i] = ::Opm::unit::convert::to(p [i], key_unit);
|
||||
rv[i] = ::Opm::unit::convert::to(rv[i], rv_unit);
|
||||
}
|
||||
|
||||
auto graph = Opm::FlowDiagnostics::Graph {
|
||||
std::move(p), std::move(rv)
|
||||
};
|
||||
|
||||
return { std::move(graph) };
|
||||
}
|
||||
|
||||
// #####################################################################
|
||||
|
||||
namespace {
|
||||
@ -480,8 +393,7 @@ public:
|
||||
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
getPvtCurve(const RegIdx region,
|
||||
const RawCurve curve,
|
||||
const ECLUnits::UnitSystem& usys) const;
|
||||
const RawCurve curve) const;
|
||||
|
||||
private:
|
||||
std::vector<EvalPtr> eval_;
|
||||
@ -551,12 +463,11 @@ viscosity(const RegIdx region,
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::Gas::Impl::
|
||||
getPvtCurve(const RegIdx region,
|
||||
const RawCurve curve,
|
||||
const ECLUnits::UnitSystem& usys) const
|
||||
const RawCurve curve) const
|
||||
{
|
||||
this->validateRegIdx(region);
|
||||
|
||||
return this->eval_[region]->getPvtCurve(curve, usys);
|
||||
return this->eval_[region]->getPvtCurve(curve);
|
||||
}
|
||||
|
||||
void
|
||||
@ -635,10 +546,9 @@ double Opm::ECLPVT::Gas::surfaceMassDensity(const int region) const
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::Gas::
|
||||
getPvtCurve(const RawCurve curve,
|
||||
const int region,
|
||||
const ECLUnits::UnitSystem& usys) const
|
||||
const int region) const
|
||||
{
|
||||
return this->pImpl_->getPvtCurve(region, curve, usys);
|
||||
return this->pImpl_->getPvtCurve(region, curve);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
|
@ -162,11 +162,6 @@ namespace Opm { namespace ECLPVT {
|
||||
/// \param[in] region Region ID. Non-negative integer typically
|
||||
/// derived from the PVTNUM mapping vector.
|
||||
///
|
||||
/// \param[in] usys Unit system. Collection of units to which the
|
||||
/// raw, tabulated PVT curve data will be converted. Usually
|
||||
/// created by function \code ECLUnits::createUnitSystem()
|
||||
/// \endcode or a similar facility.
|
||||
///
|
||||
/// \return Collection of 2D graphs for PVT property curve
|
||||
/// identified by requests represented by \p func and \p region.
|
||||
/// One curve (vector element) for each pressure node. Single
|
||||
@ -182,8 +177,7 @@ namespace Opm { namespace ECLPVT {
|
||||
/// \endcode
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
getPvtCurve(const RawCurve curve,
|
||||
const int region,
|
||||
const ECLUnits::UnitSystem& usys) const;
|
||||
const int region) const;
|
||||
|
||||
private:
|
||||
/// Implementation class.
|
||||
|
@ -96,8 +96,7 @@ public:
|
||||
const std::vector<double>& po) const = 0;
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const = 0;
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const = 0;
|
||||
|
||||
virtual std::unique_ptr<PVxOBase> clone() const = 0;
|
||||
};
|
||||
@ -132,30 +131,9 @@ public:
|
||||
}
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||
{
|
||||
if (curve == Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||
// Not applicable to dead oil. Return empty.
|
||||
return { Opm::FlowDiagnostics::Graph{} };
|
||||
}
|
||||
|
||||
auto pvtcurve = this->interpolant_.getPvtCurve(curve);
|
||||
|
||||
const auto x_unit = usys.pressure();
|
||||
const auto y_unit = (curve == ::Opm::ECLPVT::RawCurve::FVF)
|
||||
? (usys.reservoirVolume() / usys.surfaceVolumeLiquid())
|
||||
: usys.viscosity();
|
||||
|
||||
auto& x = pvtcurve.first;
|
||||
auto& y = pvtcurve.second;
|
||||
|
||||
for (auto n = x.size(), i = 0*n; i < n; ++i) {
|
||||
x[i] = ::Opm::unit::convert::to(x[i], x_unit);
|
||||
y[i] = ::Opm::unit::convert::to(y[i], y_unit);
|
||||
}
|
||||
|
||||
return { std::move(pvtcurve) };
|
||||
return { this->interpolant_.getPvtCurve(curve) };
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<PVxOBase> clone() const override
|
||||
@ -180,8 +158,7 @@ public:
|
||||
|
||||
LiveOil(std::vector<double> key,
|
||||
std::vector<SubtableInterpolant> propInterp)
|
||||
: key_ (key) // Copy
|
||||
, interp_(std::move(key), std::move(propInterp))
|
||||
: interp_(std::move(key), std::move(propInterp))
|
||||
{}
|
||||
|
||||
virtual std::vector<double>
|
||||
@ -211,14 +188,9 @@ public:
|
||||
}
|
||||
|
||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||
{
|
||||
if (curve == ::Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||
return this->saturatedStateCurve(usys);
|
||||
}
|
||||
|
||||
return this->mainPvtCurve(curve, usys);
|
||||
return this->interp_.getPvtCurve(curve);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<PVxOBase> clone() const override
|
||||
@ -229,68 +201,27 @@ public:
|
||||
private:
|
||||
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
||||
|
||||
std::vector<double> key_;
|
||||
TableInterpolant interp_;
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
mainPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const;
|
||||
repackagePvtCurve(std::vector<Opm::FlowDiagnostics::Graph>&& graphs,
|
||||
const Opm::ECLPVT::RawCurve curve) const
|
||||
{
|
||||
if (curve != Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||
// Not saturated state curve. Nothing to do here.
|
||||
return graphs;
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
saturatedStateCurve(const Opm::ECLUnits::UnitSystem& usys) const;
|
||||
// Saturated state curve for live oil. Columns are (Rs, Po). Swap
|
||||
// first and second columns to normalised form: (Po, Rs).
|
||||
for (auto& graph : graphs) {
|
||||
graph.first.swap(graph.second);
|
||||
}
|
||||
|
||||
return graphs;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
LiveOil::mainPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
||||
const Opm::ECLUnits::UnitSystem& usys) const
|
||||
{
|
||||
auto curves = this->interp_.getPvtCurve(curve);
|
||||
|
||||
const auto x_unit = usys.pressure();
|
||||
const auto y_unit = (curve == ::Opm::ECLPVT::RawCurve::FVF)
|
||||
? (usys.reservoirVolume() / usys.surfaceVolumeLiquid())
|
||||
: usys.viscosity();
|
||||
|
||||
for (auto& crv : curves) {
|
||||
auto& x = crv.first;
|
||||
auto& y = crv.second;
|
||||
|
||||
for (auto n = x.size(), i = 0*n; i < n; ++i) {
|
||||
x[i] = ::Opm::unit::convert::to(x[i], x_unit);
|
||||
y[i] = ::Opm::unit::convert::to(y[i], y_unit);
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
LiveOil::saturatedStateCurve(const Opm::ECLUnits::UnitSystem& usys) const
|
||||
{
|
||||
const auto press_unit = usys.pressure();
|
||||
const auto rs_unit = usys.dissolvedGasOilRat();
|
||||
|
||||
auto rs = this->key_;
|
||||
auto p = this->interp_.getSaturatedPoints();
|
||||
|
||||
if (rs.size() != p.size()) {
|
||||
throw std::invalid_argument {
|
||||
"Inconsistent table sizes of saturated gas function (RsSat(p))"
|
||||
};
|
||||
}
|
||||
|
||||
for (auto n = rs.size(), i = 0*n; i < n; ++i) {
|
||||
p [i] = ::Opm::unit::convert::to(p [i], press_unit);
|
||||
rs[i] = ::Opm::unit::convert::to(rs[i], rs_unit);
|
||||
}
|
||||
|
||||
auto graph = Opm::FlowDiagnostics::Graph {
|
||||
std::move(p), std::move(rs)
|
||||
};
|
||||
|
||||
return { std::move(graph) };
|
||||
}
|
||||
|
||||
// #####################################################################
|
||||
|
||||
namespace {
|
||||
@ -477,8 +408,7 @@ public:
|
||||
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
getPvtCurve(const RegIdx region,
|
||||
const RawCurve curve,
|
||||
const ECLUnits::UnitSystem& usys) const;
|
||||
const RawCurve curve) const;
|
||||
|
||||
private:
|
||||
std::vector<EvalPtr> eval_;
|
||||
@ -548,12 +478,11 @@ viscosity(const RegIdx region,
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::Oil::Impl::
|
||||
getPvtCurve(const RegIdx region,
|
||||
const RawCurve curve,
|
||||
const ECLUnits::UnitSystem& usys) const
|
||||
const RawCurve curve) const
|
||||
{
|
||||
this->validateRegIdx(region);
|
||||
|
||||
return this->eval_[region]->getPvtCurve(curve, usys);
|
||||
return this->eval_[region]->getPvtCurve(curve);
|
||||
}
|
||||
|
||||
void
|
||||
@ -632,10 +561,9 @@ double Opm::ECLPVT::Oil::surfaceMassDensity(const int region) const
|
||||
std::vector<Opm::FlowDiagnostics::Graph>
|
||||
Opm::ECLPVT::Oil::
|
||||
getPvtCurve(const RawCurve curve,
|
||||
const int region,
|
||||
const ECLUnits::UnitSystem& usys) const
|
||||
const int region) const
|
||||
{
|
||||
return this->pImpl_->getPvtCurve(region, curve, usys);
|
||||
return this->pImpl_->getPvtCurve(region, curve);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
|
@ -159,11 +159,6 @@ namespace Opm { namespace ECLPVT {
|
||||
/// \param[in] region Region ID. Non-negative integer typically
|
||||
/// derived from the PVTNUM mapping vector.
|
||||
///
|
||||
/// \param[in] usys Unit system. Collection of units to which the
|
||||
/// raw, tabulated PVT curve data will be converted. Usually
|
||||
/// created by function \code ECLUnits::createUnitSystem()
|
||||
/// \endcode or a similar facility.
|
||||
///
|
||||
/// \return Collection of 2D graphs for PVT property curve
|
||||
/// identified by requests represented by \p func and \p region.
|
||||
/// One curve (vector element) for each dissolved gas/oil ratio
|
||||
@ -179,8 +174,7 @@ namespace Opm { namespace ECLPVT {
|
||||
/// \endcode
|
||||
std::vector<FlowDiagnostics::Graph>
|
||||
getPvtCurve(const RawCurve curve,
|
||||
const int region,
|
||||
const ECLUnits::UnitSystem& usys) const;
|
||||
const int region) const;
|
||||
|
||||
private:
|
||||
/// Implementation class.
|
||||
|
@ -42,6 +42,14 @@ namespace Opm { namespace ECLUnits {
|
||||
class USys<ECL_METRIC_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
clone() const override
|
||||
{
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem> {
|
||||
new USys<ECL_METRIC_UNITS>(*this)
|
||||
};
|
||||
}
|
||||
|
||||
virtual double density() const override
|
||||
{
|
||||
return Metric::Density;
|
||||
@ -97,6 +105,14 @@ namespace Opm { namespace ECLUnits {
|
||||
class USys<ECL_FIELD_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
clone() const override
|
||||
{
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem> {
|
||||
new USys<ECL_FIELD_UNITS>(*this)
|
||||
};
|
||||
}
|
||||
|
||||
virtual double density() const override
|
||||
{
|
||||
return Field::Density;
|
||||
@ -152,6 +168,14 @@ namespace Opm { namespace ECLUnits {
|
||||
class USys<ECL_LAB_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
clone() const override
|
||||
{
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem> {
|
||||
new USys<ECL_LAB_UNITS>(*this)
|
||||
};
|
||||
}
|
||||
|
||||
virtual double density() const override
|
||||
{
|
||||
return Lab::Density;
|
||||
@ -207,6 +231,14 @@ namespace Opm { namespace ECLUnits {
|
||||
class USys<ECL_PVT_M_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<Opm::ECLUnits::UnitSystem>
|
||||
clone() const override
|
||||
{
|
||||
return std::unique_ptr<Opm::ECLUnits::UnitSystem> {
|
||||
new USys<ECL_PVT_M_UNITS>(*this)
|
||||
};
|
||||
}
|
||||
|
||||
virtual double density() const override
|
||||
{
|
||||
using namespace prefix;
|
||||
|
@ -28,6 +28,8 @@ namespace Opm {
|
||||
|
||||
struct UnitSystem
|
||||
{
|
||||
virtual std::unique_ptr<UnitSystem> clone() const = 0;
|
||||
|
||||
virtual double density() const = 0;
|
||||
virtual double depth() const = 0;
|
||||
virtual double pressure() const = 0;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user