mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-01 03:37:15 -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")
|
set(OPM_FLOWDIAGNOSTICS_SHA "7e2be931d430796ed42efcfb5c6b67a8d5962f7f")
|
||||||
|
|
||||||
# https://github.com/OPM/opm-flowdiagnostics-applications
|
# 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
|
# 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
|
# 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/ECLEndPointScaling.cpp
|
||||||
opm/utility/ECLFluxCalc.cpp
|
opm/utility/ECLFluxCalc.cpp
|
||||||
opm/utility/ECLGraph.cpp
|
opm/utility/ECLGraph.cpp
|
||||||
|
opm/utility/ECLPropertyUnitConversion.cpp
|
||||||
opm/utility/ECLPropTable.cpp
|
opm/utility/ECLPropTable.cpp
|
||||||
opm/utility/ECLPvtCommon.cpp
|
opm/utility/ECLPvtCommon.cpp
|
||||||
opm/utility/ECLPvtCurveCollection.cpp
|
opm/utility/ECLPvtCurveCollection.cpp
|
||||||
@ -41,6 +42,7 @@ list (APPEND MAIN_SOURCE_FILES
|
|||||||
|
|
||||||
list (APPEND TEST_SOURCE_FILES
|
list (APPEND TEST_SOURCE_FILES
|
||||||
tests/test_eclendpointscaling.cpp
|
tests/test_eclendpointscaling.cpp
|
||||||
|
tests/test_eclpropertyunitconversion.cpp
|
||||||
tests/test_eclproptable.cpp
|
tests/test_eclproptable.cpp
|
||||||
tests/test_eclpvtcommon.cpp
|
tests/test_eclpvtcommon.cpp
|
||||||
tests/test_eclregionmapping.cpp
|
tests/test_eclregionmapping.cpp
|
||||||
@ -54,6 +56,7 @@ list (APPEND EXAMPLE_SOURCE_FILES
|
|||||||
examples/computePhaseFluxes.cpp
|
examples/computePhaseFluxes.cpp
|
||||||
examples/computeToFandTracers.cpp
|
examples/computeToFandTracers.cpp
|
||||||
examples/computeTracers.cpp
|
examples/computeTracers.cpp
|
||||||
|
examples/dynamicCellProperty.cpp
|
||||||
examples/extractFromRestart.cpp
|
examples/extractFromRestart.cpp
|
||||||
examples/extractPropCurves.cpp
|
examples/extractPropCurves.cpp
|
||||||
tests/runAcceptanceTest.cpp
|
tests/runAcceptanceTest.cpp
|
||||||
@ -68,6 +71,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
|||||||
opm/utility/ECLGraph.hpp
|
opm/utility/ECLGraph.hpp
|
||||||
opm/utility/ECLPhaseIndex.hpp
|
opm/utility/ECLPhaseIndex.hpp
|
||||||
opm/utility/ECLPiecewiseLinearInterpolant.hpp
|
opm/utility/ECLPiecewiseLinearInterpolant.hpp
|
||||||
|
opm/utility/ECLPropertyUnitConversion.hpp
|
||||||
opm/utility/ECLPropTable.hpp
|
opm/utility/ECLPropTable.hpp
|
||||||
opm/utility/ECLPvtCommon.hpp
|
opm/utility/ECLPvtCommon.hpp
|
||||||
opm/utility/ECLPvtCurveCollection.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
|
inline Opm::FlowDiagnostics::Toolbox
|
||||||
initToolbox(const Opm::ECLGraph& G)
|
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::FlowDiagnostics::Graph
|
||||||
Opm::ECLPVT::PVDx::getPvtCurve(const RawCurve curve) const
|
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);
|
return extractRawPVTCurve(this->interp_, curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,28 +669,11 @@ namespace Opm { namespace ECLPVT {
|
|||||||
std::vector<FlowDiagnostics::Graph>
|
std::vector<FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const RawCurve curve) const
|
getPvtCurve(const RawCurve curve) const
|
||||||
{
|
{
|
||||||
auto ret = std::vector<FlowDiagnostics::Graph>{};
|
if (curve == RawCurve::SaturatedState) {
|
||||||
ret.reserve(this->propInterp_.size());
|
return this->saturatedStateCurve();
|
||||||
|
|
||||||
for (const auto& interp : this->propInterp_) {
|
|
||||||
ret.push_back(extractRawPVTCurve(interp, curve));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return this->mainPvtCurve(curve);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -844,6 +827,37 @@ namespace Opm { namespace ECLPVT {
|
|||||||
|
|
||||||
return result;
|
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.
|
/// Extract component mass density at surface conditions.
|
||||||
|
@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
#include <opm/utility/ECLPvtCurveCollection.hpp>
|
#include <opm/utility/ECLPvtCurveCollection.hpp>
|
||||||
|
|
||||||
|
#include <opm/utility/ECLPropertyUnitConversion.hpp>
|
||||||
#include <opm/utility/ECLResultData.hpp>
|
#include <opm/utility/ECLResultData.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -42,61 +44,252 @@ namespace {
|
|||||||
return pvtnum;
|
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()
|
std::vector<Opm::FlowDiagnostics::Graph> emptyFDGraph()
|
||||||
{
|
{
|
||||||
return { Opm::FlowDiagnostics::Graph{} };
|
return { Opm::FlowDiagnostics::Graph{} };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class PvtPtr>
|
template <class PVTInterp>
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
rawPvtCurve(PvtPtr& pvt, // ref to shared_ptr<>
|
rawPvtCurve(const PVTInterp* pvt,
|
||||||
const Opm::ECLPVT::RawCurve curve,
|
const Opm::ECLPVT::RawCurve curve,
|
||||||
const int regID,
|
const int regID)
|
||||||
const Opm::ECLUnits::UnitSystem& usys)
|
|
||||||
{
|
{
|
||||||
if (pvt != nullptr) {
|
if (pvt == nullptr) {
|
||||||
return pvt->getPvtCurve(curve, regID, usys);
|
// Result set does not provide requisite tabulated properties.
|
||||||
|
// Return empty.
|
||||||
|
return emptyFDGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result set does not provide requisite tabulated properties.
|
return pvt->getPvtCurve(curve, regID);
|
||||||
// Return empty.
|
}
|
||||||
return emptyFDGraph();
|
|
||||||
|
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::
|
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||||
ECLPvtCurveCollection(const ECLGraph& G,
|
ECLPvtCurveCollection(const ECLGraph& G,
|
||||||
const ECLInitFileData& init)
|
const ECLInitFileData& init)
|
||||||
: pvtnum_(pvtnumVector(G, init))
|
: pvtnum_ (pvtnumVector(G, init))
|
||||||
, gas_ (CreateGasPVTInterpolant::fromECLOutput(init)) // u_p<> -> s_p<>
|
, gas_ (CreateGasPVTInterpolant::fromECLOutput(init))
|
||||||
, oil_ (CreateOilPVTInterpolant::fromECLOutput(init)) // u_p<> -> s_p<>
|
, oil_ (CreateOilPVTInterpolant::fromECLOutput(init))
|
||||||
, usys_ (createUnitSystem(init)) // u_p<> -> s_p<>
|
, 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>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
Opm::ECLPVT::ECLPvtCurveCollection::
|
Opm::ECLPVT::ECLPvtCurveCollection::
|
||||||
getPvtCurve(const RawCurve curve,
|
getPvtCurve(const RawCurve curve,
|
||||||
const ECLPhaseIndex phase,
|
const ECLPhaseIndex phase,
|
||||||
const int activeCell) const
|
const int activeCell) const
|
||||||
{
|
{
|
||||||
if (phase == ECLPhaseIndex::Aqua) {
|
if (! this->isValidRequest(phase, activeCell)) {
|
||||||
// Not supported at this time.
|
// Not a supported phase or cell index out of bounds. Not a valid
|
||||||
// Return empty.
|
// request so return empty.
|
||||||
return emptyFDGraph();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<decltype(this->pvtnum_.size())>(activeCell)
|
|
||||||
>= this->pvtnum_.size())
|
|
||||||
{
|
|
||||||
// Active cell index out of bounds. Return empty.
|
|
||||||
return emptyFDGraph();
|
return emptyFDGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,9 +299,180 @@ getPvtCurve(const RawCurve curve,
|
|||||||
|
|
||||||
if (phase == ECLPhaseIndex::Liquid) {
|
if (phase == ECLPhaseIndex::Liquid) {
|
||||||
// Caller requests oil properties.
|
// 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.
|
// Caller requests gas properties.
|
||||||
return rawPvtCurve(this->gas_, curve, regID, *this->usys_);
|
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/ECLGraph.hpp>
|
||||||
#include <opm/utility/ECLPhaseIndex.hpp>
|
#include <opm/utility/ECLPhaseIndex.hpp>
|
||||||
|
#include <opm/utility/ECLPropertyUnitConversion.hpp>
|
||||||
#include <opm/utility/ECLPvtCommon.hpp>
|
#include <opm/utility/ECLPvtCommon.hpp>
|
||||||
#include <opm/utility/ECLPvtGas.hpp>
|
#include <opm/utility/ECLPvtGas.hpp>
|
||||||
#include <opm/utility/ECLPvtOil.hpp>
|
#include <opm/utility/ECLPvtOil.hpp>
|
||||||
@ -58,6 +59,20 @@ namespace Opm { namespace ECLPVT {
|
|||||||
ECLPvtCurveCollection(const ECLGraph& G,
|
ECLPvtCurveCollection(const ECLGraph& G,
|
||||||
const ECLInitFileData& init);
|
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
|
/// Retrieve 2D graph representation of Phase PVT property function
|
||||||
/// in a specific active cell.
|
/// in a specific active cell.
|
||||||
///
|
///
|
||||||
@ -66,14 +81,16 @@ namespace Opm { namespace ECLPVT {
|
|||||||
/// \param[in] phase Phase for which to compute extract graph
|
/// \param[in] phase Phase for which to compute extract graph
|
||||||
/// representation of PVT property function.
|
/// 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
|
/// \return Collection of 2D graphs for PVT property curve
|
||||||
/// identified by requests represented by \p curve, \p phase and
|
/// identified by requests represented by \p curve, \p phase and
|
||||||
/// \p activeCell. One curve (vector element) for each tabulated
|
/// \p activeCell. One curve (vector element) for each tabulated
|
||||||
/// node of the primary look-up key. Single curve (i.e., a
|
/// node of the primary look-up key. Single curve (i.e., a
|
||||||
/// single element vector) in the case of dry gas (no vaporised
|
/// 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
|
/// No curves for water or dead oil with constant compressibility
|
||||||
/// (i.e., keyword 'PVCDO' in the input deck).
|
/// (i.e., keyword 'PVCDO' in the input deck).
|
||||||
@ -91,6 +108,110 @@ namespace Opm { namespace ECLPVT {
|
|||||||
const ECLPhaseIndex phase,
|
const ECLPhaseIndex phase,
|
||||||
const int activeCell) const;
|
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:
|
private:
|
||||||
/// Forward map: Cell -> PVT Region ID
|
/// Forward map: Cell -> PVT Region ID
|
||||||
std::vector<int> pvtnum_;
|
std::vector<int> pvtnum_;
|
||||||
@ -101,8 +222,44 @@ namespace Opm { namespace ECLPVT {
|
|||||||
/// Oil PVT property evaluator.
|
/// Oil PVT property evaluator.
|
||||||
std::shared_ptr<Oil> oil_;
|
std::shared_ptr<Oil> oil_;
|
||||||
|
|
||||||
/// Unit handling (SI -> result-set convention)
|
/// Native unit system of INIT file. Used in the implementation of
|
||||||
std::shared_ptr<const ECLUnits::UnitSystem> usys_;
|
/// 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
|
}} // Opm::ECLPVT
|
||||||
|
@ -99,8 +99,7 @@ public:
|
|||||||
const std::vector<double>& pg) const = 0;
|
const std::vector<double>& pg) const = 0;
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const = 0;
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const = 0;
|
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxGBase> clone() const = 0;
|
virtual std::unique_ptr<PVxGBase> clone() const = 0;
|
||||||
};
|
};
|
||||||
@ -135,30 +134,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
|
||||||
{
|
{
|
||||||
if (curve == Opm::ECLPVT::RawCurve::SaturatedState) {
|
return { this->interpolant_.getPvtCurve(curve) };
|
||||||
// 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) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxGBase> clone() const override
|
virtual std::unique_ptr<PVxGBase> clone() const override
|
||||||
@ -183,8 +161,7 @@ public:
|
|||||||
|
|
||||||
WetGas(std::vector<double> key,
|
WetGas(std::vector<double> key,
|
||||||
std::vector<SubtableInterpolant> propInterp)
|
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>
|
virtual std::vector<double>
|
||||||
@ -214,14 +191,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
|
||||||
{
|
{
|
||||||
if (curve == ::Opm::ECLPVT::RawCurve::SaturatedState) {
|
return this->interp_.getPvtCurve(curve);
|
||||||
return this->saturatedStateCurve(usys);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->mainPvtCurve(curve, usys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxGBase> clone() const override
|
virtual std::unique_ptr<PVxGBase> clone() const override
|
||||||
@ -232,68 +204,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
||||||
|
|
||||||
std::vector<double> key_;
|
TableInterpolant interp_;
|
||||||
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 {
|
namespace {
|
||||||
@ -479,9 +392,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FlowDiagnostics::Graph>
|
std::vector<FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const RegIdx region,
|
getPvtCurve(const RegIdx region,
|
||||||
const RawCurve curve,
|
const RawCurve curve) const;
|
||||||
const ECLUnits::UnitSystem& usys) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<EvalPtr> eval_;
|
std::vector<EvalPtr> eval_;
|
||||||
@ -550,13 +462,12 @@ viscosity(const RegIdx region,
|
|||||||
|
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
Opm::ECLPVT::Gas::Impl::
|
Opm::ECLPVT::Gas::Impl::
|
||||||
getPvtCurve(const RegIdx region,
|
getPvtCurve(const RegIdx region,
|
||||||
const RawCurve curve,
|
const RawCurve curve) const
|
||||||
const ECLUnits::UnitSystem& usys) const
|
|
||||||
{
|
{
|
||||||
this->validateRegIdx(region);
|
this->validateRegIdx(region);
|
||||||
|
|
||||||
return this->eval_[region]->getPvtCurve(curve, usys);
|
return this->eval_[region]->getPvtCurve(curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -634,11 +545,10 @@ double Opm::ECLPVT::Gas::surfaceMassDensity(const int region) const
|
|||||||
|
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
Opm::ECLPVT::Gas::
|
Opm::ECLPVT::Gas::
|
||||||
getPvtCurve(const RawCurve curve,
|
getPvtCurve(const RawCurve curve,
|
||||||
const int region,
|
const int region) const
|
||||||
const ECLUnits::UnitSystem& usys) 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
|
/// \param[in] region Region ID. Non-negative integer typically
|
||||||
/// derived from the PVTNUM mapping vector.
|
/// 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
|
/// \return Collection of 2D graphs for PVT property curve
|
||||||
/// identified by requests represented by \p func and \p region.
|
/// identified by requests represented by \p func and \p region.
|
||||||
/// One curve (vector element) for each pressure node. Single
|
/// One curve (vector element) for each pressure node. Single
|
||||||
@ -181,9 +176,8 @@ namespace Opm { namespace ECLPVT {
|
|||||||
/// pvtGas.getPvtCurve(ECLPVT::RawCurve::FVF, 0);
|
/// pvtGas.getPvtCurve(ECLPVT::RawCurve::FVF, 0);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
std::vector<FlowDiagnostics::Graph>
|
std::vector<FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const RawCurve curve,
|
getPvtCurve(const RawCurve curve,
|
||||||
const int region,
|
const int region) const;
|
||||||
const ECLUnits::UnitSystem& usys) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Implementation class.
|
/// Implementation class.
|
||||||
|
@ -96,8 +96,7 @@ public:
|
|||||||
const std::vector<double>& po) const = 0;
|
const std::vector<double>& po) const = 0;
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const = 0;
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const = 0;
|
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxOBase> clone() const = 0;
|
virtual std::unique_ptr<PVxOBase> clone() const = 0;
|
||||||
};
|
};
|
||||||
@ -132,30 +131,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
|
||||||
{
|
{
|
||||||
if (curve == Opm::ECLPVT::RawCurve::SaturatedState) {
|
return { this->interpolant_.getPvtCurve(curve) };
|
||||||
// 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) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxOBase> clone() const override
|
virtual std::unique_ptr<PVxOBase> clone() const override
|
||||||
@ -180,8 +158,7 @@ public:
|
|||||||
|
|
||||||
LiveOil(std::vector<double> key,
|
LiveOil(std::vector<double> key,
|
||||||
std::vector<SubtableInterpolant> propInterp)
|
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>
|
virtual std::vector<double>
|
||||||
@ -211,14 +188,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
virtual std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
getPvtCurve(const Opm::ECLPVT::RawCurve curve) const override
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const override
|
|
||||||
{
|
{
|
||||||
if (curve == ::Opm::ECLPVT::RawCurve::SaturatedState) {
|
return this->interp_.getPvtCurve(curve);
|
||||||
return this->saturatedStateCurve(usys);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->mainPvtCurve(curve, usys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<PVxOBase> clone() const override
|
virtual std::unique_ptr<PVxOBase> clone() const override
|
||||||
@ -229,67 +201,26 @@ public:
|
|||||||
private:
|
private:
|
||||||
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
using TableInterpolant = ::Opm::ECLPVT::PVTx<SubtableInterpolant>;
|
||||||
|
|
||||||
std::vector<double> key_;
|
TableInterpolant interp_;
|
||||||
TableInterpolant interp_;
|
|
||||||
|
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
mainPvtCurve(const Opm::ECLPVT::RawCurve curve,
|
repackagePvtCurve(std::vector<Opm::FlowDiagnostics::Graph>&& graphs,
|
||||||
const Opm::ECLUnits::UnitSystem& usys) const;
|
const Opm::ECLPVT::RawCurve curve) const
|
||||||
|
{
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
if (curve != Opm::ECLPVT::RawCurve::SaturatedState) {
|
||||||
saturatedStateCurve(const Opm::ECLUnits::UnitSystem& usys) const;
|
// Not saturated state curve. Nothing to do here.
|
||||||
};
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
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) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// #####################################################################
|
// #####################################################################
|
||||||
|
|
||||||
@ -476,9 +407,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FlowDiagnostics::Graph>
|
std::vector<FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const RegIdx region,
|
getPvtCurve(const RegIdx region,
|
||||||
const RawCurve curve,
|
const RawCurve curve) const;
|
||||||
const ECLUnits::UnitSystem& usys) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<EvalPtr> eval_;
|
std::vector<EvalPtr> eval_;
|
||||||
@ -547,13 +477,12 @@ viscosity(const RegIdx region,
|
|||||||
|
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
Opm::ECLPVT::Oil::Impl::
|
Opm::ECLPVT::Oil::Impl::
|
||||||
getPvtCurve(const RegIdx region,
|
getPvtCurve(const RegIdx region,
|
||||||
const RawCurve curve,
|
const RawCurve curve) const
|
||||||
const ECLUnits::UnitSystem& usys) const
|
|
||||||
{
|
{
|
||||||
this->validateRegIdx(region);
|
this->validateRegIdx(region);
|
||||||
|
|
||||||
return this->eval_[region]->getPvtCurve(curve, usys);
|
return this->eval_[region]->getPvtCurve(curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -631,11 +560,10 @@ double Opm::ECLPVT::Oil::surfaceMassDensity(const int region) const
|
|||||||
|
|
||||||
std::vector<Opm::FlowDiagnostics::Graph>
|
std::vector<Opm::FlowDiagnostics::Graph>
|
||||||
Opm::ECLPVT::Oil::
|
Opm::ECLPVT::Oil::
|
||||||
getPvtCurve(const RawCurve curve,
|
getPvtCurve(const RawCurve curve,
|
||||||
const int region,
|
const int region) const
|
||||||
const ECLUnits::UnitSystem& usys) 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
|
/// \param[in] region Region ID. Non-negative integer typically
|
||||||
/// derived from the PVTNUM mapping vector.
|
/// 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
|
/// \return Collection of 2D graphs for PVT property curve
|
||||||
/// identified by requests represented by \p func and \p region.
|
/// identified by requests represented by \p func and \p region.
|
||||||
/// One curve (vector element) for each dissolved gas/oil ratio
|
/// One curve (vector element) for each dissolved gas/oil ratio
|
||||||
@ -178,9 +173,8 @@ namespace Opm { namespace ECLPVT {
|
|||||||
/// pvtOil.getPvtCurve(ECLPVT::RawCurve::Viscosity, 3);
|
/// pvtOil.getPvtCurve(ECLPVT::RawCurve::Viscosity, 3);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
std::vector<FlowDiagnostics::Graph>
|
std::vector<FlowDiagnostics::Graph>
|
||||||
getPvtCurve(const RawCurve curve,
|
getPvtCurve(const RawCurve curve,
|
||||||
const int region,
|
const int region) const;
|
||||||
const ECLUnits::UnitSystem& usys) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Implementation class.
|
/// Implementation class.
|
||||||
|
@ -42,6 +42,14 @@ namespace Opm { namespace ECLUnits {
|
|||||||
class USys<ECL_METRIC_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
class USys<ECL_METRIC_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual double density() const override
|
||||||
{
|
{
|
||||||
return Metric::Density;
|
return Metric::Density;
|
||||||
@ -97,6 +105,14 @@ namespace Opm { namespace ECLUnits {
|
|||||||
class USys<ECL_FIELD_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
class USys<ECL_FIELD_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual double density() const override
|
||||||
{
|
{
|
||||||
return Field::Density;
|
return Field::Density;
|
||||||
@ -152,6 +168,14 @@ namespace Opm { namespace ECLUnits {
|
|||||||
class USys<ECL_LAB_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
class USys<ECL_LAB_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual double density() const override
|
||||||
{
|
{
|
||||||
return Lab::Density;
|
return Lab::Density;
|
||||||
@ -207,6 +231,14 @@ namespace Opm { namespace ECLUnits {
|
|||||||
class USys<ECL_PVT_M_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
class USys<ECL_PVT_M_UNITS> : public ::Opm::ECLUnits::UnitSystem
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual double density() const override
|
||||||
{
|
{
|
||||||
using namespace prefix;
|
using namespace prefix;
|
||||||
|
@ -28,6 +28,8 @@ namespace Opm {
|
|||||||
|
|
||||||
struct UnitSystem
|
struct UnitSystem
|
||||||
{
|
{
|
||||||
|
virtual std::unique_ptr<UnitSystem> clone() const = 0;
|
||||||
|
|
||||||
virtual double density() const = 0;
|
virtual double density() const = 0;
|
||||||
virtual double depth() const = 0;
|
virtual double depth() const = 0;
|
||||||
virtual double pressure() 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