Merge from upstream.

This commit is contained in:
Bård Skaflestad 2012-01-03 20:39:52 +01:00
commit 403cf40dd0
30 changed files with 3596 additions and 42 deletions

View File

@ -37,3 +37,5 @@ tests/test_cfs_tpfa
tests/test_jacsys
tests/test_readvector
tests/test_sf2p
tests/bo_fluid_p_and_z_deps
tests/bo_fluid_pressuredeps

1
.hgtags Normal file
View File

@ -0,0 +1 @@
b3cc85c2b5ab3f5b283244624d06a1afab9f8d67 Version-InitialImport-svn935

View File

@ -3,12 +3,25 @@ ACLOCAL_AMFLAGS = -I m4
# Recurse to build examples after libraries
SUBDIRS = . tests examples
CPPFLAGS += $(BOOST_CPPFLAGS)
LIBS += $(BOOST_LDFLAGS) \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \
$(BOOST_DATE_TIME_LIB) \
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
# Declare libraries
lib_LTLIBRARIES = libopmcore.la
libopmcore_la_SOURCES = \
libopmcore_la_SOURCES = \
opm/core/eclipse/EclipseGridInspector.cpp \
opm/core/eclipse/EclipseGridParser.cpp \
opm/core/fluid/blackoil/BlackoilPVT.cpp \
opm/core/fluid/blackoil/MiscibilityDead.cpp \
opm/core/fluid/blackoil/MiscibilityLiveGas.cpp \
opm/core/fluid/blackoil/MiscibilityLiveOil.cpp \
opm/core/fluid/blackoil/MiscibilityProps.cpp \
opm/core/utility/MonotCubicInterpolator.cpp \
opm/core/utility/parameters/Parameter.cpp \
opm/core/utility/parameters/ParameterGroup.cpp \
@ -18,21 +31,21 @@ opm/core/utility/parameters/tinyxml/tinystr.cpp \
opm/core/utility/parameters/tinyxml/tinyxml.cpp \
opm/core/utility/parameters/tinyxml/tinyxmlerror.cpp \
opm/core/utility/parameters/tinyxml/tinyxmlparser.cpp \
opm/core/utility/cart_grid.c \
opm/core/utility/cpgpreprocess/geometry.c \
opm/core/utility/cpgpreprocess/preprocess.c \
opm/core/utility/cpgpreprocess/readvector.cpp \
opm/core/utility/cpgpreprocess/cgridinterface.c \
opm/core/utility/cpgpreprocess/sparsetable.c \
opm/core/utility/cpgpreprocess/facetopology.c \
opm/core/utility/cpgpreprocess/uniquepoints.c \
opm/core/utility/cart_grid.c \
opm/core/utility/cpgpreprocess/geometry.c \
opm/core/utility/cpgpreprocess/preprocess.c \
opm/core/utility/cpgpreprocess/readvector.cpp \
opm/core/utility/cpgpreprocess/cgridinterface.c \
opm/core/utility/cpgpreprocess/sparsetable.c \
opm/core/utility/cpgpreprocess/facetopology.c \
opm/core/utility/cpgpreprocess/uniquepoints.c \
opm/core/utility/StopWatch.cpp \
opm/core/linalg/sparse_sys.c \
opm/core/pressure/cfsh.c \
opm/core/pressure/flow_bc.c \
opm/core/pressure/well.c \
opm/core/pressure/fsh_common_impl.c \
opm/core/pressure/fsh.c \
opm/core/linalg/sparse_sys.c \
opm/core/pressure/cfsh.c \
opm/core/pressure/flow_bc.c \
opm/core/pressure/well.c \
opm/core/pressure/fsh_common_impl.c \
opm/core/pressure/fsh.c \
opm/core/pressure/tpfa/ifs_tpfa.c \
opm/core/pressure/tpfa/compr_source.c \
opm/core/pressure/tpfa/cfs_tpfa.c \
@ -62,10 +75,20 @@ opm/core/eclipse/EclipseGridParser.hpp \
opm/core/eclipse/EclipseGridParserHelpers.hpp \
opm/core/eclipse/EclipseUnits.hpp \
opm/core/eclipse/SpecialEclipseFields.hpp \
opm/core/fluid/BlackoilFluid.hpp \
opm/core/fluid/SimpleFluid2p.hpp \
opm/core/fluid/blackoil/BlackoilDefs.hpp \
opm/core/fluid/blackoil/BlackoilPVT.hpp \
opm/core/fluid/blackoil/FluidMatrixInteractionBlackoil.hpp \
opm/core/fluid/blackoil/FluidStateBlackoil.hpp \
opm/core/fluid/blackoil/MiscibilityDead.hpp \
opm/core/fluid/blackoil/MiscibilityLiveGas.hpp \
opm/core/fluid/blackoil/MiscibilityLiveOil.hpp \
opm/core/fluid/blackoil/MiscibilityProps.hpp \
opm/core/fluid/blackoil/MiscibilityWater.hpp \
opm/core/utility/Average.hpp \
opm/core/utility/ErrorMacros.hpp \
opm/core/utility/Factory.hpp \
opm/core/utility/linInt.hpp \
opm/core/utility/MonotCubicInterpolator.hpp \
opm/core/utility/parameters/Parameter.hpp \
opm/core/utility/parameters/ParameterGroup.hpp \
@ -81,7 +104,11 @@ opm/core/utility/RootFinders.hpp \
opm/core/utility/SparseTable.hpp \
opm/core/utility/SparseVector.hpp \
opm/core/utility/StopWatch.hpp \
opm/core/utility/UniformTableLinear.hpp \
opm/core/utility/Units.hpp \
opm/core/utility/buildUniformMonotoneTable.hpp \
opm/core/utility/linInt.hpp \
opm/core/utility/linearInterpolation.hpp \
opm/core/utility/cpgpreprocess/readvector.hpp \
opm/core/utility/cpgpreprocess/uniquepoints.h \
opm/core/utility/cpgpreprocess/preprocess.h \
@ -95,7 +122,6 @@ opm/core/utility/cart_grid.h \
opm/core/well.h \
opm/core/linalg/sparse_sys.h \
opm/core/linalg/blas_lapack.h \
opm/core/fluid/SimpleFluid2p.hpp \
opm/core/grid.h \
opm/core/GridAdapter.hpp \
opm/core/pressure/fsh.h \

View File

@ -4,13 +4,7 @@ $(BOOST_CPPFLAGS)
LDFLAGS = $(BOOST_LDFLAGS)
LDADD = \
$(top_builddir)/libopmcore.la \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \
$(BOOST_DATE_TIME_LIB) \
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS)
LDADD = $(top_builddir)/libopmcore.la
noinst_PROGRAMS = \
scaneclipsedeck

View File

@ -83,7 +83,7 @@ namespace EclipseKeywords
string("BULKMOD"), string("YOUNGMOD"), string("LAMEMOD"),
string("SHEARMOD"), string("POISSONMOD"), string("PWAVEMOD"),
string("MULTPV"), string("PRESSURE"), string("SGAS"),
string("SWAT")
string("SWAT"), string("SOIL")
};
const int num_floating_fields = sizeof(floating_fields) / sizeof(floating_fields[0]);
@ -95,7 +95,7 @@ namespace EclipseKeywords
string("SGOF"), string("SWOF"), string("ROCK"),
string("ROCKTAB"), string("WELSPECS"), string("COMPDAT"),
string("WCONINJE"), string("WCONPROD"), string("WELTARG"),
string("EQUIL"), string("PVCDO"),
string("EQUIL"), string("PVCDO"), string("TSTEP"),
// The following fields only have a dummy implementation
// that allows us to ignore them.
"SWFN",
@ -111,7 +111,7 @@ namespace EclipseKeywords
string("NSTACK"), string("SATNUM"),
string("RPTRST"), string("ROIP"), string("RWIP"),
string("RWSAT"), string("RPR"), string("WBHP"),
string("WOIR"), string("TSTEP"), string("BOX"),
string("WOIR"), string("BOX"),
string("COORDSYS"), string("PBVD")
};
const int num_ignore_with_data = sizeof(ignore_with_data) / sizeof(ignore_with_data[0]);
@ -249,11 +249,18 @@ void EclipseGridParser::readImpl(istream& is)
readVectorData(is, floatmap[keyword]);
break;
case SpecialField: {
std::tr1::shared_ptr<SpecialBase> sb_ptr = createSpecialField(is, keyword);
if (sb_ptr) {
specialmap[keyword] = sb_ptr;
map<string, std::tr1::shared_ptr<SpecialBase> >::iterator pos =
specialmap.find(keyword);
if (pos == specialmap.end()) {
std::tr1::shared_ptr<SpecialBase> sb_ptr =
createSpecialField(is, keyword);
if (sb_ptr) {
specialmap[keyword] = sb_ptr;
} else {
THROW("Could not create field " << keyword);
}
} else {
THROW("Could not create field " << keyword);
pos->second->read(is);
}
break;
}
@ -341,7 +348,7 @@ void EclipseGridParser::convertToSI()
} else if (key == "PORO" || key == "BULKMOD" || key == "YOUNGMOD" ||
key == "LAMEMOD" || key == "SHEARMOD" || key == "POISSONMOD" ||
key == "PWAVEMOD" || key == "MULTPV" || key == "PWAVEMOD" ||
key == "SGAS" || key == "SWAT") {
key == "SGAS" || key == "SWAT" || key == "SOIL") {
unit = 1.0;
} else if (key == "PRESSURE") {
unit = units_.pressure;

View File

@ -142,6 +142,7 @@ public:
SPECIAL_FIELD(WELTARG);
SPECIAL_FIELD(EQUIL);
SPECIAL_FIELD(PVCDO);
SPECIAL_FIELD(TSTEP);
// The following fields only have a dummy implementation
// that allows us to ignore them.

View File

@ -868,7 +868,7 @@ struct CompdatLine
skin_factor_(0.0),
D_factor_(-1e100),
penetration_direct_("Z"),
r0_(0.0)
r0_(-1.0)
{
grid_ind_.resize(4);
}
@ -1018,13 +1018,18 @@ struct WCONINJE : public SpecialBase
double_data[2] = wconinje_line.BHP_limit_;
double_data[4] = wconinje_line.VFP_table_number_;
double_data[5] = wconinje_line.concentration_;
readDefaultedVectorData(is, double_data, 6);
const int num_to_read = 6;
int num_read = readDefaultedVectorData(is, double_data, num_to_read);
wconinje_line.surface_flow_max_rate_ = double_data[0];
wconinje_line.fluid_volume_max_rate_ = double_data[1];
wconinje_line.BHP_limit_ = double_data[2];
wconinje_line.THP_limit_ = double_data[3];
wconinje_line.VFP_table_number_ = (int)double_data[4];
wconinje_line.concentration_ = double_data[5];
// HACK! Ignore any further items
if (num_read == num_to_read) {
ignoreSlashLine(is);
}
wconinje.push_back(wconinje_line);
}
}
@ -1127,7 +1132,8 @@ struct WCONPROD : public SpecialBase
double_data[6] = wconprod_line.THP_limit_;
double_data[7] = wconprod_line.VFP_table_number_;
double_data[8] = wconprod_line.artif_lift_quantity_;
readDefaultedVectorData(is, double_data, 9);
const int num_to_read = 9;
int num_read = readDefaultedVectorData(is, double_data, num_to_read);
wconprod_line.oil_max_rate_ = double_data[0];
wconprod_line.water_max_rate_ = double_data[1];
wconprod_line.gas_max_rate_ = double_data[2];
@ -1138,6 +1144,11 @@ struct WCONPROD : public SpecialBase
wconprod_line.VFP_table_number_ = (int)double_data[7];
wconprod_line.artif_lift_quantity_ = double_data[8];
wconprod.push_back(wconprod_line);
// HACK! Ignore any further items
if (num_read == num_to_read) {
ignoreSlashLine(is);
}
}
}
@ -1408,6 +1419,38 @@ struct PVCDO : public SpecialBase
}
};
struct TSTEP : public SpecialBase
{
std::vector<double> tstep_;
virtual std::string name() const {return std::string("TSTEP");}
virtual void read(std::istream& is)
{
std::vector<double> tstep;
readVectorData(is, tstep);
if (!tstep.empty()) {
tstep_.insert(tstep_.end(), tstep.begin(), tstep.end());
}
}
virtual void write(std::ostream& os) const
{
os << name() << '\n';
copy(tstep_.begin(), tstep_.end(),
std::ostream_iterator<double>(os, " "));
os << '\n';
}
virtual void convertToSI(const EclipseUnits& units)
{
int num_steps = tstep_.size();
for (int i = 0; i < num_steps; ++i) {
tstep_[i] *= units.time;
}
}
};
struct MultRec : public SpecialBase
{
virtual void read(std::istream& is)

View File

@ -0,0 +1,609 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_BLACKOILFLUID_HEADER_INCLUDED
#define OPM_BLACKOILFLUID_HEADER_INCLUDED
#include <opm/core/fluid/blackoil/FluidMatrixInteractionBlackoil.hpp>
#include <opm/core/fluid/blackoil/FluidStateBlackoil.hpp>
#include <opm/core/fluid/blackoil/BlackoilPVT.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <vector>
namespace Opm
{
/// Forward declaration for typedef i BlackoilFluid.
class BlackoilFluidData;
/// Class responsible for computing all fluid properties from
/// face pressures and composition.
class BlackoilFluid : public BlackoilDefs
{
public:
typedef FluidStateBlackoil FluidState;
typedef BlackoilFluidData FluidData;
void init(const Dune::EclipseGridParser& parser)
{
fmi_params_.init(parser);
// FluidSystemBlackoil<>::init(parser);
pvt_.init(parser);
const std::vector<double>& dens = parser.getDENSITY().densities_[0];
surface_densities_[Oil] = dens[0];
surface_densities_[Water] = dens[1];
surface_densities_[Gas] = dens[2];
}
FluidState computeState(PhaseVec phase_pressure, CompVec z) const
{
FluidState state;
state.temperature_ = 300;
state.phase_pressure_ = phase_pressure;
state.surface_volume_ = z;
// FluidSystemBlackoil<>::computeEquilibrium(state); // Sets everything but relperm and mobility.
computeEquilibrium(state);
FluidMatrixInteractionBlackoil<double>::kr(state.relperm_, fmi_params_, state.saturation_, state.temperature_);
FluidMatrixInteractionBlackoil<double>::dkr(state.drelperm_, fmi_params_, state.saturation_, state.temperature_);
for (int phase = 0; phase < numPhases; ++phase) {
state.mobility_[phase] = state.relperm_[phase]/state.viscosity_[phase];
for (int p2 = 0; p2 < numPhases; ++p2) {
// Ignoring pressure variation in viscosity for this one.
state.dmobility_[phase][p2] = state.drelperm_[phase][p2]/state.viscosity_[phase];
}
}
return state;
}
const CompVec& surfaceDensities() const
{
return surface_densities_;
}
/// \param[in] A state matrix in fortran ordering
PhaseVec phaseDensities(const double* A) const
{
PhaseVec phase_dens(0.0);
for (int phase = 0; phase < numPhases; ++phase) {
for (int comp = 0; comp < numComponents; ++comp) {
phase_dens[phase] += A[numComponents*phase + comp]*surface_densities_[comp];
}
}
return phase_dens;
}
// ---- New interface ----
/// Input: p, z
/// Output: B, R
template <class States>
void computeBAndR(States& states) const
{
const std::vector<PhaseVec>& p = states.phase_pressure;
const std::vector<CompVec>& z = states.surface_volume_density;
std::vector<PhaseVec>& B = states.formation_volume_factor;
std::vector<PhaseVec>& R = states.solution_factor;
pvt_.B(p, z, B);
pvt_.R(p, z, R);
}
/// Input: p, z
/// Output: B, R, mu
template <class States>
void computePvtNoDerivs(States& states) const
{
computeBAndR(states);
const std::vector<PhaseVec>& p = states.phase_pressure;
const std::vector<CompVec>& z = states.surface_volume_density;
std::vector<PhaseVec>& mu = states.viscosity;
pvt_.getViscosity(p, z, mu);
}
/// Input: p, z
/// Output: B, dB/dp, R, dR/dp, mu
template <class States>
void computePvt(States& states) const
{
const std::vector<PhaseVec>& p = states.phase_pressure;
const std::vector<CompVec>& z = states.surface_volume_density;
std::vector<PhaseVec>& B = states.formation_volume_factor;
std::vector<PhaseVec>& dB = states.formation_volume_factor_deriv;
std::vector<PhaseVec>& R = states.solution_factor;
std::vector<PhaseVec>& dR = states.solution_factor_deriv;
std::vector<PhaseVec>& mu = states.viscosity;
pvt_.dBdp(p, z, B, dB);
pvt_.dRdp(p, z, R, dR);
pvt_.getViscosity(p, z, mu);
}
/// Input: B, R
/// Output: A
template <class States>
void computeStateMatrix(States& states) const
{
int num = states.formation_volume_factor.size();
states.state_matrix.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
const PhaseVec& B = states.formation_volume_factor[i];
const PhaseVec& R = states.solution_factor[i];
PhaseToCompMatrix& At = states.state_matrix[i];
// Set the A matrix (A = RB^{-1})
// Using A transposed (At) since we really want Fortran ordering:
// ultimately that is what the opmpressure C library expects.
At = 0.0;
At[Aqua][Water] = 1.0/B[Aqua];
At[Vapour][Gas] = 1.0/B[Vapour];
At[Liquid][Gas] = R[Liquid]/B[Liquid];
At[Vapour][Oil] = R[Vapour]/B[Vapour];
At[Liquid][Oil] = 1.0/B[Liquid];
}
}
/// Input: z, B, dB/dp, R, dR/dp
/// Output: A, u, sum(u), s, c, cT, ex
template <class States>
void computePvtDepending(States& states) const
{
int num = states.formation_volume_factor.size();
states.state_matrix.resize(num);
states.phase_volume_density.resize(num);
states.total_phase_volume_density.resize(num);
states.saturation.resize(num);
#ifdef COMPUTE_OLD_TERMS
states.phase_compressibility.resize(num);
states.total_compressibility.resize(num);
states.experimental_term.resize(num);
#endif
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
const CompVec& z = states.surface_volume_density[i];
const PhaseVec& B = states.formation_volume_factor[i];
const PhaseVec& R = states.solution_factor[i];
PhaseToCompMatrix& At = states.state_matrix[i];
PhaseVec& u = states.phase_volume_density[i];
double& tot_phase_vol_dens = states.total_phase_volume_density[i];
PhaseVec& s = states.saturation[i];
#ifdef COMPUTE_OLD_TERMS
const PhaseVec& dB = states.formation_volume_factor_deriv[i];
const PhaseVec& dR = states.solution_factor_deriv[i];
PhaseVec& cp = states.phase_compressibility[i];
double& tot_comp = states.total_compressibility[i];
double& exp_term = states.experimental_term[i];
computeSingleEquilibrium(B, dB, R, dR, z,
At, u, tot_phase_vol_dens,
s, cp, tot_comp, exp_term);
#else
computeSingleEquilibrium(B, R, z,
At, u, tot_phase_vol_dens,
s);
#endif
}
}
/// Input: s, mu
/// Output: kr, lambda
template <class States>
void computeMobilitiesNoDerivs(States& states) const
{
int num = states.saturation.size();
states.relperm.resize(num);
states.mobility.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
const CompVec& s = states.saturation[i];
const PhaseVec& mu = states.viscosity[i];
PhaseVec& kr = states.relperm[i];
PhaseVec& lambda = states.mobility[i];
FluidMatrixInteractionBlackoil<double>::kr(kr, fmi_params_, s, 300.0);
for (int phase = 0; phase < numPhases; ++phase) {
lambda[phase] = kr[phase]/mu[phase];
}
}
}
/// Input: s, mu
/// Output: kr, dkr/ds, lambda, dlambda/ds
template <class States>
void computeMobilities(States& states) const
{
int num = states.saturation.size();
states.relperm.resize(num);
states.relperm_deriv.resize(num);
states.mobility.resize(num);
states.mobility_deriv.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
const CompVec& s = states.saturation[i];
const PhaseVec& mu = states.viscosity[i];
PhaseVec& kr = states.relperm[i];
PhaseJacobian& dkr = states.relperm_deriv[i];
PhaseVec& lambda = states.mobility[i];
PhaseJacobian& dlambda = states.mobility_deriv[i];
FluidMatrixInteractionBlackoil<double>::kr(kr, fmi_params_, s, 300.0);
FluidMatrixInteractionBlackoil<double>::dkr(dkr, fmi_params_, s, 300.0);
for (int phase = 0; phase < numPhases; ++phase) {
lambda[phase] = kr[phase]/mu[phase];
for (int p2 = 0; p2 < numPhases; ++p2) {
// Ignoring pressure variation in viscosity for this one.
dlambda[phase][p2] = dkr[phase][p2]/mu[phase];
}
}
}
}
private:
BlackoilPVT pvt_;
FluidMatrixInteractionBlackoilParams<double> fmi_params_;
CompVec surface_densities_;
/*!
* \brief Assuming the surface volumes and the pressures of all
* phases are known, compute everything except relperm and
* mobility.
*/
template <class FluidState>
void computeEquilibrium(FluidState& fluid_state) const
{
// Get B and R factors.
const PhaseVec& p = fluid_state.phase_pressure_;
const CompVec& z = fluid_state.surface_volume_;
PhaseVec& B = fluid_state.formation_volume_factor_;
B[Aqua] = pvt_.B(p[Aqua], z, Aqua);
B[Vapour] = pvt_.B(p[Vapour], z, Vapour);
B[Liquid] = pvt_.B(p[Liquid], z, Liquid);
PhaseVec& R = fluid_state.solution_factor_;
R[Aqua] = 0.0;
R[Vapour] = pvt_.R(p[Vapour], z, Vapour);
R[Liquid] = pvt_.R(p[Liquid], z, Liquid);
// Convenience vars.
PhaseToCompMatrix& At = fluid_state.phase_to_comp_;
PhaseVec& u = fluid_state.phase_volume_density_;
double& tot_phase_vol_dens = fluid_state.total_phase_volume_density_;
PhaseVec& s = fluid_state.saturation_;
#ifdef COMPUTE_OLD_TERMS
PhaseVec dB;
dB[Aqua] = pvt_.dBdp(p[Aqua], z, Aqua);
dB[Vapour] = pvt_.dBdp(p[Vapour], z, Vapour);
dB[Liquid] = pvt_.dBdp(p[Liquid], z, Liquid);
PhaseVec dR;
dR[Aqua] = 0.0;
dR[Vapour] = pvt_.dRdp(p[Vapour], z, Vapour);
dR[Liquid] = pvt_.dRdp(p[Liquid], z, Liquid);
PhaseVec& cp = fluid_state.phase_compressibility_;
double& tot_comp = fluid_state.total_compressibility_;
double& exp_term = fluid_state.experimental_term_;
computeSingleEquilibrium(B, dB, R, dR, z,
At, u, tot_phase_vol_dens,
s, cp, tot_comp, exp_term);
#else
computeSingleEquilibrium(B, R, z,
At, u, tot_phase_vol_dens,
s);
#endif
// Compute viscosities.
PhaseVec& mu = fluid_state.viscosity_;
mu[Aqua] = pvt_.getViscosity(p[Aqua], z, Aqua);
mu[Vapour] = pvt_.getViscosity(p[Vapour], z, Vapour);
mu[Liquid] = pvt_.getViscosity(p[Liquid], z, Liquid);
}
#ifdef COMPUTE_OLD_TERMS
static void computeSingleEquilibrium(const PhaseVec& B,
const PhaseVec& dB,
const PhaseVec& R,
const PhaseVec& dR,
const CompVec& z,
PhaseToCompMatrix& At,
PhaseVec& u,
double& tot_phase_vol_dens,
PhaseVec& s,
PhaseVec& cp,
double& tot_comp,
double& exp_term)
#else
static void computeSingleEquilibrium(const PhaseVec& B,
const PhaseVec& R,
const CompVec& z,
PhaseToCompMatrix& At,
PhaseVec& u,
double& tot_phase_vol_dens,
PhaseVec& s)
#endif
{
// Set the A matrix (A = RB^{-1})
// Using At since we really want Fortran ordering
// (since ultimately that is what the opmpressure
// C library expects).
// PhaseToCompMatrix& At = fluid_state.phase_to_comp_[i];
At = 0.0;
At[Aqua][Water] = 1.0/B[Aqua];
At[Vapour][Gas] = 1.0/B[Vapour];
At[Liquid][Gas] = R[Liquid]/B[Liquid];
At[Vapour][Oil] = R[Vapour]/B[Vapour];
At[Liquid][Oil] = 1.0/B[Liquid];
// Update phase volumes. This is the same as multiplying with A^{-1}
// PhaseVec& u = fluid_state.phase_volume_density_[i];
double detR = 1.0 - R[Vapour]*R[Liquid];
u[Aqua] = B[Aqua]*z[Water];
u[Vapour] = B[Vapour]*(z[Gas] - R[Liquid]*z[Oil])/detR;
u[Liquid] = B[Liquid]*(z[Oil] - R[Vapour]*z[Gas])/detR;
tot_phase_vol_dens = u[Aqua] + u[Vapour] + u[Liquid];
// PhaseVec& s = fluid_state.saturation_[i];
for (int phase = 0; phase < numPhases; ++phase) {
s[phase] = u[phase]/tot_phase_vol_dens;
}
#ifdef COMPUTE_OLD_TERMS
// Phase compressibilities.
// PhaseVec& cp = fluid_state.phase_compressibility_[i];
// Set the derivative of the A matrix (A = RB^{-1})
PhaseToCompMatrix dAt(0.0);
dAt[Aqua][Water] = -dB[Aqua]/(B[Aqua]*B[Aqua]);
dAt[Vapour][Gas] = -dB[Vapour]/(B[Vapour]*B[Vapour]);
dAt[Liquid][Oil] = -dB[Liquid]/(B[Liquid]*B[Liquid]); // Different order than above.
dAt[Liquid][Gas] = dAt[Liquid][Oil]*R[Liquid] + dR[Liquid]/B[Liquid];
dAt[Vapour][Oil] = dAt[Vapour][Gas]*R[Vapour] + dR[Vapour]/B[Vapour];
PhaseToCompMatrix Ait;
Dune::FMatrixHelp::invertMatrix(At, Ait);
PhaseToCompMatrix Ct;
Dune::FMatrixHelp::multMatrix(dAt, Ait, Ct);
cp[Aqua] = Ct[Aqua][Water];
cp[Liquid] = Ct[Liquid][Oil] + Ct[Liquid][Gas];
cp[Vapour] = Ct[Vapour][Gas] + Ct[Vapour][Oil];
tot_comp = cp*s;
// Experimental term.
PhaseVec tmp1, tmp2, tmp3;
Ait.mtv(z, tmp1);
dAt.mtv(tmp1, tmp2);
Ait.mtv(tmp2, tmp3);
exp_term = tmp3[Aqua] + tmp3[Liquid] + tmp3[Gas];
#endif
}
};
struct FaceFluidData : public BlackoilDefs
{
// Canonical state variables.
std::vector<CompVec> surface_volume_density; // z
std::vector<PhaseVec> phase_pressure; // p
// Variables from PVT functions.
std::vector<PhaseVec> formation_volume_factor; // B
std::vector<PhaseVec> solution_factor; // R
// Variables computed from PVT data.
// The A matrices are all in Fortran order (or, equivalently,
// we store the transposes).
std::vector<PhaseToCompMatrix> state_matrix; // A' = (RB^{-1})'
// Variables computed from saturation.
std::vector<PhaseVec> mobility; // lambda
std::vector<PhaseJacobian> mobility_deriv; // dlambda/ds
// Gravity and/or capillary pressure potential differences.
std::vector<PhaseVec> gravity_potential; // (\rho g \delta z)-ish contribution per face
};
struct AllFluidData : public BlackoilDefs
{
// Per-cell data
AllFluidStates cell_data;
std::vector<double> voldiscr;
std::vector<double> relvoldiscr;
// Per-face data.
FaceFluidData face_data;
public:
template <class Grid, class Rock>
void computeNew(const Grid& grid,
const Rock& rock,
const BlackoilFluid& fluid,
const typename Grid::Vector gravity,
const std::vector<PhaseVec>& cell_pressure,
const std::vector<PhaseVec>& face_pressure,
const std::vector<CompVec>& cell_z,
const CompVec& bdy_z,
const double dt)
{
int num_cells = cell_z.size();
ASSERT(num_cells == grid.numCells());
const int np = numPhases;
const int nc = numComponents;
BOOST_STATIC_ASSERT(np == nc);
BOOST_STATIC_ASSERT(np == 3);
// p, z -> B, dB, R, dR, mu, A, dA, u, sum(u), s, c, cT, ex, kr, dkr, lambda, dlambda.
cell_data.phase_pressure = cell_pressure;
cell_data.surface_volume_density = cell_z;
fluid.computePvt(cell_data);
fluid.computePvtDepending(cell_data);
fluid.computeMobilities(cell_data);
// Compute volume discrepancies.
voldiscr.resize(num_cells);
relvoldiscr.resize(num_cells);
#pragma omp parallel for
for (int cell = 0; cell < num_cells; ++cell) {
double pv = rock.porosity(cell)*grid.cellVolume(cell);
voldiscr[cell] = (cell_data.total_phase_volume_density[cell] - 1.0)*pv/dt;
relvoldiscr[cell] = std::fabs(cell_data.total_phase_volume_density[cell] - 1.0);
}
// Compute upwinded face properties, including z.
computeUpwindProperties(grid, fluid, gravity,
cell_pressure, face_pressure,
cell_z, bdy_z);
// Compute state matrices for faces.
// p, z -> B, R, A
face_data.phase_pressure = face_pressure;
fluid.computeBAndR(face_data);
fluid.computeStateMatrix(face_data);
}
template <class Grid>
void computeUpwindProperties(const Grid& grid,
const BlackoilFluid& fluid,
const typename Grid::Vector gravity,
const std::vector<PhaseVec>& cell_pressure,
const std::vector<PhaseVec>& face_pressure,
const std::vector<CompVec>& cell_z,
const CompVec& bdy_z)
{
int num_faces = face_pressure.size();
ASSERT(num_faces == grid.numFaces());
bool nonzero_gravity = gravity.two_norm() > 0.0;
face_data.state_matrix.resize(num_faces);
face_data.mobility.resize(num_faces);
face_data.mobility_deriv.resize(num_faces);
face_data.gravity_potential.resize(num_faces);
face_data.surface_volume_density.resize(num_faces);
#pragma omp parallel for
for (int face = 0; face < num_faces; ++face) {
// Obtain properties from both sides of the face.
typedef typename Grid::Vector Vec;
Vec fc = grid.faceCentroid(face);
int c[2] = { grid.faceCell(face, 0), grid.faceCell(face, 1) };
// Get pressures and compute gravity contributions,
// to decide upwind directions.
PhaseVec phase_p[2];
PhaseVec gravcontrib[2];
for (int j = 0; j < 2; ++j) {
if (c[j] >= 0) {
// Pressures
phase_p[j] = cell_pressure[c[j]];
// Gravity contribution.
if (nonzero_gravity) {
Vec cdiff = fc;
cdiff -= grid.cellCentroid(c[j]);
gravcontrib[j] = fluid.phaseDensities(&cell_data.state_matrix[c[j]][0][0]);
gravcontrib[j] *= (cdiff*gravity);
} else {
gravcontrib[j] = 0.0;
}
} else {
// Pressures
phase_p[j] = face_pressure[face];
// Gravity contribution.
gravcontrib[j] = 0.0;
}
}
// Gravity contribution:
// gravcapf = rho_1*g*(z_12 - z_1) - rho_2*g*(z_12 - z_2)
// where _1 and _2 refers to two neigbour cells, z is the
// z coordinate of the centroid, and z_12 is the face centroid.
// Also compute the potentials.
PhaseVec pot[2];
for (int phase = 0; phase < numPhases; ++phase) {
face_data.gravity_potential[face][phase] = gravcontrib[0][phase] - gravcontrib[1][phase];
pot[0][phase] = phase_p[0][phase] + face_data.gravity_potential[face][phase];
pot[1][phase] = phase_p[1][phase];
}
// Now we can easily find the upwind direction for every phase,
// we can also tell which boundary faces are inflow bdys.
// Compute face_z, which is averaged from the cells, unless on outflow or noflow bdy.
// Get mobilities and derivatives.
CompVec face_z(0.0);
double face_z_factor = 0.5;
PhaseVec phase_mob[2];
PhaseJacobian phasemob_deriv[2];
for (int j = 0; j < 2; ++j) {
if (c[j] >= 0) {
face_z += cell_z[c[j]];
phase_mob[j] = cell_data.mobility[c[j]];
phasemob_deriv[j] = cell_data.mobility_deriv[c[j]];
} else if (pot[j][Liquid] > pot[(j+1)%2][Liquid]) {
// Inflow boundary.
face_z += bdy_z;
FluidStateBlackoil bdy_state = fluid.computeState(face_pressure[face], bdy_z);
phase_mob[j] = bdy_state.mobility_;
phasemob_deriv[j] = bdy_state.dmobility_;
} else {
// For outflow or noflow boundaries, only cell z is used.
face_z_factor = 1.0;
// Also, make sure the boundary data are not used for mobilities.
pot[j] = -1e100;
}
}
face_z *= face_z_factor;
face_data.surface_volume_density[face] = face_z;
// Computing upwind mobilities and derivatives
for (int phase = 0; phase < numPhases; ++phase) {
if (pot[0][phase] == pot[1][phase]) {
// Average.
double aver = 0.5*(phase_mob[0][phase] + phase_mob[1][phase]);
face_data.mobility[face][phase] = aver;
for (int p2 = 0; p2 < numPhases; ++p2) {
face_data.mobility_deriv[face][phase][p2] = phasemob_deriv[0][phase][p2]
+ phasemob_deriv[1][phase][p2];
}
} else {
// Upwind.
int upwind = pot[0][phase] > pot[1][phase] ? 0 : 1;
face_data.mobility[face][phase] = phase_mob[upwind][phase];
for (int p2 = 0; p2 < numPhases; ++p2) {
face_data.mobility_deriv[face][phase][p2] = phasemob_deriv[upwind][phase][p2];
}
}
}
}
}
};
} // namespace Opm
#endif // OPM_BLACKOILFLUID_HEADER_INCLUDED

View File

@ -0,0 +1,101 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_BLACKOILDEFS_HEADER_INCLUDED
#define OPM_BLACKOILDEFS_HEADER_INCLUDED
#include <tr1/array>
#include <iostream>
#include <boost/static_assert.hpp>
namespace Opm
{
class BlackoilDefs
{
public:
enum { numComponents = 3 };
enum { numPhases = 3 };
enum ComponentIndex { Water = 0, Oil = 1, Gas = 2 };
enum PhaseIndex { Aqua = 0, Liquid = 1, Vapour = 2 };
// We need types with operator= and constructor taking scalars
// for the small vectors and matrices, to save us from having to
// rewrite a large amount of code.
template <typename T, int N>
class SmallVec
{
public:
SmallVec()
{}
SmallVec(const T& elem)
{ assign(elem); }
SmallVec& operator=(const T& elem)
{ assign(elem); return *this; }
const T& operator[](int i) const
{ return data_[i]; }
T& operator[](int i)
{ return data_[i]; }
template <typename U>
void assign(const U& elem)
{
for (int i = 0; i < N; ++i) {
data_[i] = elem;
}
}
private:
T data_[N];
};
template <typename T, int Rows, int Cols>
class SmallMat
{
public:
SmallMat()
{}
SmallMat(const T& elem)
{ data_.assign(elem); }
SmallMat& operator=(const T& elem)
{ data_.assign(elem); return *this; }
typedef SmallVec<T, Cols> RowType;
const RowType& operator[](int i) const
{ return data_[i]; }
RowType& operator[](int i)
{ return data_[i]; }
private:
SmallVec<RowType, Rows> data_;
};
typedef double Scalar;
typedef SmallVec<Scalar, numComponents> CompVec;
typedef SmallVec<Scalar, numPhases> PhaseVec;
BOOST_STATIC_ASSERT(int(numComponents) == int(numPhases));
typedef SmallMat<Scalar, numComponents, numPhases> PhaseToCompMatrix;
typedef SmallMat<Scalar, numPhases, numPhases> PhaseJacobian;
// Attempting to guard against alignment issues.
BOOST_STATIC_ASSERT(sizeof(CompVec) == numComponents*sizeof(Scalar));
BOOST_STATIC_ASSERT(sizeof(PhaseVec) == numPhases*sizeof(Scalar));
BOOST_STATIC_ASSERT(sizeof(PhaseToCompMatrix) == numComponents*numPhases*sizeof(Scalar));
BOOST_STATIC_ASSERT(sizeof(PhaseJacobian) == numPhases*numPhases*sizeof(Scalar));
};
} // namespace Opm
#endif // OPM_BLACKOILDEFS_HEADER_INCLUDED

View File

@ -0,0 +1,202 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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/core/fluid/blackoil/BlackoilPVT.hpp>
#include <opm/core/fluid/blackoil/MiscibilityDead.hpp>
#include <opm/core/fluid/blackoil/MiscibilityLiveOil.hpp>
#include <opm/core/fluid/blackoil/MiscibilityLiveGas.hpp>
#include <opm/core/fluid/blackoil/MiscibilityWater.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/linInt.hpp>
using namespace Dune;
namespace Opm
{
void BlackoilPVT::init(const Dune::EclipseGridParser& parser)
{
typedef std::vector<std::vector<std::vector<double> > > table_t;
region_number_ = 0;
// Surface densities. Accounting for different orders in eclipse and our code.
if (parser.hasField("DENSITY")) {
const int region_number = 0;
enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
const std::vector<double>& d = parser.getDENSITY().densities_[region_number];
densities_[Aqua] = d[ECL_water];
densities_[Vapour] = d[ECL_gas];
densities_[Liquid] = d[ECL_oil];
} else {
THROW("Input is missing DENSITY\n");
}
// Water PVT
if (parser.hasField("PVTW")) {
water_props_.reset(new MiscibilityWater(parser.getPVTW().pvtw_));
} else {
water_props_.reset(new MiscibilityWater(0.5*Dune::prefix::centi*Dune::unit::Poise)); // Eclipse 100 default
}
// Oil PVT
if (parser.hasField("PVDO")) {
oil_props_.reset(new MiscibilityDead(parser.getPVDO().pvdo_));
} else if (parser.hasField("PVTO")) {
oil_props_.reset(new MiscibilityLiveOil(parser.getPVTO().pvto_));
} else if (parser.hasField("PVCDO")) {
oil_props_.reset(new MiscibilityWater(parser.getPVCDO().pvcdo_));
} else {
THROW("Input is missing PVDO and PVTO\n");
}
// Gas PVT
if (parser.hasField("PVDG")) {
gas_props_.reset(new MiscibilityDead(parser.getPVDG().pvdg_));
} else if (parser.hasField("PVTG")) {
gas_props_.reset(new MiscibilityLiveGas(parser.getPVTG().pvtg_));
} else {
THROW("Input is missing PVDG and PVTG\n");
}
}
BlackoilPVT::CompVec BlackoilPVT::surfaceDensities() const
{
return densities_;
}
double BlackoilPVT::getViscosity(double press, const CompVec& surfvol, PhaseIndex phase) const
{
return propsForPhase(phase).getViscosity(region_number_, press, surfvol);
}
double BlackoilPVT::B(double press, const CompVec& surfvol, PhaseIndex phase) const
{
return propsForPhase(phase).B(region_number_, press, surfvol);
}
double BlackoilPVT::dBdp(double press, const CompVec& surfvol, PhaseIndex phase) const
{
return propsForPhase(phase).dBdp(region_number_, press, surfvol);
}
double BlackoilPVT::R(double press, const CompVec& surfvol, PhaseIndex phase) const
{
return propsForPhase(phase).R(region_number_, press, surfvol);
}
double BlackoilPVT::dRdp(double press, const CompVec& surfvol, PhaseIndex phase) const
{
return propsForPhase(phase).dRdp(region_number_, press, surfvol);
}
const MiscibilityProps& BlackoilPVT::propsForPhase(PhaseIndex phase) const
{
switch (phase) {
case Aqua:
return *water_props_;
case Liquid:
return *oil_props_;
case Vapour:
return *gas_props_;
default:
THROW("Unknown phase accessed: " << phase);
}
}
void BlackoilPVT::getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const
{
int num = pressures.size();
output.resize(num);
for (int phase = 0; phase < numPhases; ++phase) {
propsForPhase(PhaseIndex(phase)).getViscosity(pressures, surfvol, phase, data1_);
for (int i = 0; i < num; ++i) {
output[i][phase] = data1_[i];
}
}
}
void BlackoilPVT::B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const
{
int num = pressures.size();
output.resize(num);
for (int phase = 0; phase < numPhases; ++phase) {
propsForPhase(PhaseIndex(phase)).B(pressures, surfvol, phase, data1_);
for (int i = 0; i < num; ++i) {
output[i][phase] = data1_[i];
}
}
}
void BlackoilPVT::dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output_B,
std::vector<PhaseVec>& output_dBdp) const
{
int num = pressures.size();
output_B.resize(num);
output_dBdp.resize(num);
for (int phase = 0; phase < numPhases; ++phase) {
propsForPhase(PhaseIndex(phase)).dBdp(pressures, surfvol, phase, data1_, data2_);
for (int i = 0; i < num; ++i) {
output_B[i][phase] = data1_[i];
output_dBdp[i][phase] = data2_[i];
}
}
}
void BlackoilPVT::R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const
{
int num = pressures.size();
output.resize(num);
for (int phase = 0; phase < numPhases; ++phase) {
propsForPhase(PhaseIndex(phase)).R(pressures, surfvol, phase, data1_);
for (int i = 0; i < num; ++i) {
output[i][phase] = data1_[i];
}
}
}
void BlackoilPVT::dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output_R,
std::vector<PhaseVec>& output_dRdp) const
{
int num = pressures.size();
output_R.resize(num);
output_dRdp.resize(num);
for (int phase = 0; phase < numPhases; ++phase) {
propsForPhase(PhaseIndex(phase)).dRdp(pressures, surfvol, phase, data1_, data2_);
for (int i = 0; i < num; ++i) {
output_R[i][phase] = data1_[i];
output_dRdp[i][phase] = data2_[i];
}
}
}
} // namespace Opm

View File

@ -0,0 +1,88 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_BLACKOILPVT_HEADER_INCLUDED
#define OPM_BLACKOILPVT_HEADER_INCLUDED
#include <opm/core/fluid/blackoil/MiscibilityProps.hpp>
#include <opm/core/fluid/blackoil/BlackoilDefs.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <boost/scoped_ptr.hpp>
#include <string>
namespace Opm
{
class BlackoilPVT : public BlackoilDefs
{
public:
void init(const Dune::EclipseGridParser& ep);
double getViscosity(double press,
const CompVec& surfvol,
PhaseIndex phase) const;
CompVec surfaceDensities() const;
double B (double press,
const CompVec& surfvol,
PhaseIndex phase) const;
double dBdp(double press,
const CompVec& surfvol,
PhaseIndex phase) const;
double R (double press,
const CompVec& surfvol,
PhaseIndex phase) const;
double dRdp(double press,
const CompVec& surfvol,
PhaseIndex phase) const;
void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const;
void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const;
void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output_B,
std::vector<PhaseVec>& output_dBdp) const;
void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output) const;
void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
std::vector<PhaseVec>& output_R,
std::vector<PhaseVec>& output_dRdp) const;
private:
int region_number_;
const MiscibilityProps& propsForPhase(PhaseIndex phase) const;
boost::scoped_ptr<MiscibilityProps> water_props_;
boost::scoped_ptr<MiscibilityProps> oil_props_;
boost::scoped_ptr<MiscibilityProps> gas_props_;
CompVec densities_;
mutable std::vector<double> data1_;
mutable std::vector<double> data2_;
};
}
#endif // OPM_BLACKOILPVT_HEADER_INCLUDED

View File

@ -0,0 +1,208 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_FLUIDMATRIXINTERACTIONBLACKOIL_HEADER_INCLUDED
#define OPM_FLUIDMATRIXINTERACTIONBLACKOIL_HEADER_INCLUDED
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <opm/core/fluid/blackoil/BlackoilDefs.hpp>
#include <iostream>
#include <stdexcept>
namespace Opm
{
// Forward declaration needed by associated parameters class.
template <class ScalarT, class ParamsT>
class FluidMatrixInteractionBlackoil;
template <class ScalarT>
class FluidMatrixInteractionBlackoilParams
{
public:
typedef ScalarT Scalar;
void init(const Dune::EclipseGridParser& ep)
{
// Extract input data.
const Dune::SGOF::table_t& sgof_table = ep.getSGOF().sgof_;
const Dune::SWOF::table_t& swof_table = ep.getSWOF().swof_;
if (sgof_table.size() != 1 || swof_table.size() != 1) {
std::cerr << "We must have exactly one SWOF and one SGOF table (at the moment).\n";
throw std::logic_error("Not implemented");
}
const std::vector<double>& sw = swof_table[0][0];
const std::vector<double>& krw = swof_table[0][1];
const std::vector<double>& krow = swof_table[0][2];
const std::vector<double>& pcow = swof_table[0][3];
const std::vector<double>& sg = sgof_table[0][0];
const std::vector<double>& krg = sgof_table[0][1];
const std::vector<double>& krog = sgof_table[0][2];
const std::vector<double>& pcog = sgof_table[0][3];
// Create tables for krw, krow, krg and krog.
int samples = 200;
buildUniformMonotoneTable(sw, krw, samples, krw_);
buildUniformMonotoneTable(sw, krow, samples, krow_);
buildUniformMonotoneTable(sg, krg, samples, krg_);
buildUniformMonotoneTable(sg, krog, samples, krog_);
krocw_ = krow[0]; // At connate water -> ecl. SWOF
// Create tables for pcow and pcog.
buildUniformMonotoneTable(sw, pcow, samples, pcow_);
buildUniformMonotoneTable(sg, pcog, samples, pcog_);
}
private:
template <class S, class P>
friend class FluidMatrixInteractionBlackoil;
Dune::utils::UniformTableLinear<Scalar> krw_;
Dune::utils::UniformTableLinear<Scalar> krow_;
Dune::utils::UniformTableLinear<Scalar> pcow_;
Dune::utils::UniformTableLinear<Scalar> krg_;
Dune::utils::UniformTableLinear<Scalar> krog_;
Dune::utils::UniformTableLinear<Scalar> pcog_;
Scalar krocw_; // = krow_(s_wc)
};
/*!
* \ingroup material
*
* \brief Capillary pressures and relative permeabilities for a black oil system.
*/
template <class ScalarT, class ParamsT = FluidMatrixInteractionBlackoilParams<ScalarT> >
class FluidMatrixInteractionBlackoil : public BlackoilDefs
{
public:
typedef ParamsT Params;
typedef typename Params::Scalar Scalar;
/*!
* \brief The linear capillary pressure-saturation curve.
*
* This material law is linear:
* \f[
p_C = (1 - \overline{S}_w) (p_{C,max} - p_{C,entry}) + p_{C,entry}
\f]
*
* \param Swe Effective saturation of of the wetting phase \f$\overline{S}_w\f$
*/
template <class pcContainerT, class SatContainerT>
static void pC(pcContainerT &pc,
const Params &params,
const SatContainerT &saturations,
Scalar /*temperature*/)
{
Scalar sw = saturations[Aqua];
Scalar sg = saturations[Vapour];
pc[Liquid] = 0.0;
pc[Aqua] = params.pcow_(sw);
pc[Vapour] = params.pcog_(sg);
}
/*!
* \brief The saturation-capillary pressure curve.
*
* This is the inverse of the capillary pressure-saturation curve:
* \f[
S_w = 1 - \frac{p_C - p_{C,entry}}{p_{C,max} - p_{C,entry}}
\f]
*
* \param pC Capillary pressure \f$\p_C\f$
* \return The effective saturaion of the wetting phase \f$\overline{S}_w\f$
*/
template <class SatContainerT, class pcContainerT>
static void S(SatContainerT &saturations,
const Params &params,
const pcContainerT &pc,
Scalar /*temperature*/)
{
std::cerr << "FluidMatrixInteractionBlackoil::S() is not implemented yet\n";
throw std::logic_error("Not implemented");
}
/*!
* \brief The relative permeability of all phases.
*/
template <class krContainerT, class SatContainerT>
static void kr(krContainerT &kr,
const Params &params,
const SatContainerT &saturations,
Scalar /*temperature*/)
{
// Stone-II relative permeability model.
Scalar sw = saturations[Aqua];
Scalar sg = saturations[Vapour];
Scalar krw = params.krw_(sw);
Scalar krg = params.krg_(sg);
Scalar krow = params.krow_(sw);
Scalar krog = params.krog_(sg);
Scalar krocw = params.krocw_;
kr[Aqua] = krw;
kr[Vapour] = krg;
kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
if (kr[Liquid] < 0.0) {
kr[Liquid] = 0.0;
}
}
/*!
* \brief The saturation derivatives of relative permeability of all phases.
*/
template <class krContainerT, class SatContainerT>
static void dkr(krContainerT &dkr,
const Params &params,
const SatContainerT &saturations,
Scalar /*temperature*/)
{
for (int p1 = 0; p1 < numPhases; ++p1) {
for (int p2 = 0; p2 < numPhases; ++p2) {
dkr[p1][p2] = 0.0;
}
}
// Stone-II relative permeability model.
Scalar sw = saturations[Aqua];
Scalar sg = saturations[Vapour];
Scalar krw = params.krw_(sw);
Scalar dkrww = params.krw_.derivative(sw);
Scalar krg = params.krg_(sg);
Scalar dkrgg = params.krg_.derivative(sg);
Scalar krow = params.krow_(sw);
Scalar dkrow = params.krow_.derivative(sw);
Scalar krog = params.krog_(sg);
Scalar dkrog = params.krog_.derivative(sg);
Scalar krocw = params.krocw_;
dkr[Aqua][Aqua] = dkrww;
dkr[Vapour][Vapour] = dkrgg;
dkr[Liquid][Aqua] = krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
dkr[Liquid][Vapour] = krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg);
}
};
} // namespace Opm
#endif // OPM_FLUIDMATRIXINTERACTIONBLACKOIL_HEADER_INCLUDED

View File

@ -0,0 +1,95 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_FLUIDSTATEBLACKOIL_HEADER_INCLUDED
#define OPM_FLUIDSTATEBLACKOIL_HEADER_INCLUDED
#include "BlackoilDefs.hpp"
namespace Opm
{
/*!
* \brief Fluid state for a black oil model.
*/
struct FluidStateBlackoil : public BlackoilDefs
{
Scalar temperature_;
CompVec surface_volume_;
PhaseVec phase_pressure_;
PhaseVec phase_volume_density_;
Scalar total_phase_volume_density_;
PhaseVec formation_volume_factor_;
PhaseVec solution_factor_;
PhaseToCompMatrix phase_to_comp_; // RB^{-1} in Fortran ordering
PhaseVec saturation_;
#ifdef COMPUTE_OLD_TERMS
PhaseVec phase_compressibility_;
Scalar total_compressibility_;
Scalar experimental_term_;
#endif
PhaseVec viscosity_;
PhaseVec relperm_;
PhaseJacobian drelperm_;
PhaseVec mobility_;
PhaseJacobian dmobility_;
};
/*!
* \brief Multiple fluid states for a black oil model.
*/
struct AllFluidStates : public BlackoilDefs
{
// Canonical state variables.
std::vector<CompVec> surface_volume_density; // z
std::vector<PhaseVec> phase_pressure; // p
// Variables from PVT functions.
std::vector<PhaseVec> formation_volume_factor; // B
std::vector<PhaseVec> solution_factor; // R
std::vector<PhaseVec> viscosity; // mu
// Variables computed from PVT data.
// The A matrices are all in Fortran order (or, equivalently,
// we store the transposes).
std::vector<PhaseToCompMatrix> state_matrix; // A' = (RB^{-1})'
std::vector<PhaseVec> phase_volume_density; // u
std::vector<Scalar> total_phase_volume_density; // sum(u)
std::vector<PhaseVec> saturation; // s = u/sum(u)
#ifdef COMPUTE_OLD_TERMS
std::vector<PhaseVec> formation_volume_factor_deriv; // dB/dp
std::vector<PhaseVec> solution_factor_deriv; // dR/dp
std::vector<PhaseVec> phase_compressibility; // c
std::vector<Scalar> total_compressibility; // cT
std::vector<Scalar> experimental_term; // ex = sum(Ai*dA*Ai*z)
#endif
// Variables computed from saturation.
std::vector<PhaseVec> relperm; // kr
std::vector<PhaseJacobian> relperm_deriv; // dkr/ds
std::vector<PhaseVec> mobility; // lambda
std::vector<PhaseJacobian> mobility_deriv; // dlambda/ds
};
} // end namespace Opm
#endif // OPM_FLUIDSTATEBLACKOIL_HEADER_INCLUDED

View File

@ -0,0 +1,11 @@
noinst_LTLIBRARIES = libblackoilfluid_noinst.la
libblackoilfluid_noinst_la_SOURCES = \
BlackoilPVT.cpp \
MiscibilityDead.cpp \
MiscibilityLiveGas.cpp \
MiscibilityLiveOil.cpp \
MiscibilityProps.cpp
include $(top_srcdir)/am/global-rules

View File

@ -0,0 +1,179 @@
//===========================================================================
//
// File: MiscibilityDead.cpp
//
// Created: Wed Feb 10 09:06:04 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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/core/fluid/blackoil/MiscibilityDead.hpp>
#include <algorithm>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/linInt.hpp>
#include <opm/core/utility/buildUniformMonotoneTable.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <fstream>
using namespace std;
using namespace Dune;
namespace Opm
{
//------------------------------------------------------------------------
// Member functions
//-------------------------------------------------------------------------
/// Constructor
MiscibilityDead::MiscibilityDead(const table_t& pvd_table)
{
const int region_number = 0;
if (pvd_table.size() != 1) {
THROW("More than one PVT-region");
}
// Copy data
const int sz = pvd_table[region_number][0].size();
std::vector<double> press(sz);
std::vector<double> B_inv(sz);
std::vector<double> visc(sz);
for (int i = 0; i < sz; ++i) {
press[i] = pvd_table[region_number][0][i];
B_inv[i] = 1.0 / pvd_table[region_number][1][i];
visc[i] = pvd_table[region_number][2][i];
}
int samples = 1025;
buildUniformMonotoneTable(press, B_inv, samples, one_over_B_);
buildUniformMonotoneTable(press, visc, samples, viscosity_);
// Dumping the created tables.
// static int count = 0;
// std::ofstream os((std::string("dump-") + boost::lexical_cast<std::string>(count++)).c_str());
// os.precision(15);
// os << "1/B\n\n" << one_over_B_
// << "\n\nvisc\n\n" << viscosity_ << std::endl;
}
// Destructor
MiscibilityDead::~MiscibilityDead()
{
}
double MiscibilityDead::getViscosity(int /*region*/, double press, const surfvol_t& /*surfvol*/) const
{
return viscosity_(press);
}
void MiscibilityDead::getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int phase,
std::vector<double>& output) const
{
int num = pressures.size();
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output[i] = viscosity_(pressures[i][phase]);
}
}
double MiscibilityDead::B(int /*region*/, double press, const surfvol_t& /*surfvol*/) const
{
// Interpolate 1/B
return 1.0/one_over_B_(press);
}
void MiscibilityDead::B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int phase,
std::vector<double>& output) const
{
int num = pressures.size();
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output[i] = 1.0/one_over_B_(pressures[i][phase]);
}
}
double MiscibilityDead::dBdp(int region, double press, const surfvol_t& /*surfvol*/) const
{
// Interpolate 1/B
surfvol_t dummy_surfvol;
double Bg = B(region, press, dummy_surfvol);
return -Bg*Bg*one_over_B_.derivative(press);
}
void MiscibilityDead::dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvols,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const
{
B(pressures, surfvols, phase, output_B);
int num = pressures.size();
output_dBdp.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
double Bg = output_B[i];
output_dBdp[i] = -Bg*Bg*one_over_B_.derivative(pressures[i][phase]);
}
}
double MiscibilityDead::R(int /*region*/, double /*press*/, const surfvol_t& /*surfvol*/) const
{
return 0.0;
}
void MiscibilityDead::R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int,
std::vector<double>& output) const
{
int num = pressures.size();
output.clear();
output.resize(num, 0.0);
}
double MiscibilityDead::dRdp(int /*region*/, double /*press*/, const surfvol_t& /*surfvol*/) const
{
return 0.0;
}
void MiscibilityDead::dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const
{
int num = pressures.size();
output_R.clear();
output_R.resize(num, 0.0);
output_dRdp.clear();
output_dRdp.resize(num, 0.0);
}
}

View File

@ -0,0 +1,89 @@
//===========================================================================
//
// File: MiscibilityDead.hpp
//
// Created: Wed Feb 10 09:05:47 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 SINTEF_MISCIBILITYDEAD_HEADER
#define SINTEF_MISCIBILITYDEAD_HEADER
/** Class for immiscible dead oil and dry gas.
* Detailed description.
*/
#include <opm/core/fluid/blackoil/MiscibilityProps.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
namespace Opm
{
class MiscibilityDead : public MiscibilityProps
{
public:
typedef std::vector<std::vector<std::vector<double> > > table_t;
MiscibilityDead(const table_t& pvd_table);
virtual ~MiscibilityDead();
virtual double getViscosity(int region, double press, const surfvol_t& surfvol) const;
virtual double B(int region, double press, const surfvol_t& surfvol) const;
virtual double dBdp(int region, double press, const surfvol_t& surfvol) const;
virtual double R(int region, double press, const surfvol_t& surfvol) const;
virtual double dRdp(int region, double press, const surfvol_t& surfvol) const;
virtual void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const;
virtual void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const;
private:
// PVT properties of dry gas or dead oil
Dune::utils::UniformTableLinear<double> one_over_B_;
Dune::utils::UniformTableLinear<double> viscosity_;
};
}
#endif // SINTEF_MISCIBILITYDEAD_HEADER

View File

@ -0,0 +1,286 @@
//===========================================================================
//
// File: MiscibilityLiveGas.cpp
//
// Created: Wed Feb 10 09:21:53 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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/core/fluid/blackoil/MiscibilityLiveGas.hpp>
#include <algorithm>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/linInt.hpp>
using namespace std;
using namespace Dune;
namespace Opm
{
//------------------------------------------------------------------------
// Member functions
//-------------------------------------------------------------------------
/// Constructor
MiscibilityLiveGas::MiscibilityLiveGas(const table_t& pvtg)
{
// GAS, PVTG
const int region_number = 0;
if (pvtg.size() != 1) {
THROW("More than one PVD-region");
}
saturated_gas_table_.resize(4);
const int sz = pvtg[region_number].size();
for (int k=0; k<4; ++k) {
saturated_gas_table_[k].resize(sz);
}
for (int i=0; i<sz; ++i) {
saturated_gas_table_[0][i] = pvtg[region_number][i][0]; // p
saturated_gas_table_[1][i] = pvtg[region_number][i][2]; // Bg
saturated_gas_table_[2][i] = pvtg[region_number][i][3]; // mu_g
saturated_gas_table_[3][i] = pvtg[region_number][i][1]; // Rv
}
undersat_gas_tables_.resize(sz);
for (int i=0; i<sz; ++i) {
undersat_gas_tables_[i].resize(3);
int tsize = (pvtg[region_number][i].size() - 1)/3;
undersat_gas_tables_[i][0].resize(tsize);
undersat_gas_tables_[i][1].resize(tsize);
undersat_gas_tables_[i][2].resize(tsize);
for (int j=0, k=0; j<tsize; ++j) {
undersat_gas_tables_[i][0][j] = pvtg[region_number][i][++k]; // Rv
undersat_gas_tables_[i][1][j] = pvtg[region_number][i][++k]; // Bg
undersat_gas_tables_[i][2][j] = pvtg[region_number][i][++k]; // mu_g
}
}
}
// Destructor
MiscibilityLiveGas::~MiscibilityLiveGas()
{
}
double MiscibilityLiveGas::getViscosity(int /*region*/, double press, const surfvol_t& surfvol) const
{
return miscible_gas(press, surfvol, 2, false);
}
void MiscibilityLiveGas::getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
for (int i = 0; i < num; ++i) {
output[i] = miscible_gas(pressures[i][phase], surfvol[i], 2, false);
}
}
// Vaporised oil-gas ratio.
double MiscibilityLiveGas::R(int /*region*/, double press, const surfvol_t& surfvol) const
{
if (surfvol[Liquid] == 0.0) {
return 0.0;
}
double R = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press);
double maxR = surfvol[Liquid]/surfvol[Vapour];
if (R < maxR ) { // Saturated case
return R;
} else {
return maxR; // Undersaturated case
}
}
void MiscibilityLiveGas::R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
for (int i = 0; i < num; ++i) {
output[i] = R(0, pressures[i][phase], surfvol[i]);
}
}
// Vaporised oil-gas ratio derivative
double MiscibilityLiveGas::dRdp(int /*region*/, double press, const surfvol_t& surfvol) const
{
double R = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press);
double maxR = surfvol[Liquid]/surfvol[Vapour];
if (R < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_gas_table_[0],
saturated_gas_table_[3],
press);
} else {
return 0.0; // Undersaturated case
}
}
void MiscibilityLiveGas::dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const
{
ASSERT(pressures.size() == surfvol.size());
R(pressures, surfvol, phase, output_R);
int num = pressures.size();
output_dRdp.resize(num);
for (int i = 0; i < num; ++i) {
output_dRdp[i] = dRdp(0, pressures[i][phase], surfvol[i]); // \TODO Speedup here by using already evaluated R.
}
}
double MiscibilityLiveGas::B(int /*region*/, double press, const surfvol_t& surfvol) const
{
if (surfvol[Vapour] == 0.0) return 1.0; // To handle no-gas case.
return miscible_gas(press, surfvol, 1, false);
}
void MiscibilityLiveGas::B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
for (int i = 0; i < num; ++i) {
output[i] = B(0, pressures[i][phase], surfvol[i]);
}
}
double MiscibilityLiveGas::dBdp(int /*region*/, double press, const surfvol_t& surfvol) const
{
if (surfvol[Vapour] == 0.0) return 0.0; // To handle no-gas case.
return miscible_gas(press, surfvol, 1, true);
}
void MiscibilityLiveGas::dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const
{
ASSERT(pressures.size() == surfvol.size());
B(pressures, surfvol, phase, output_B);
int num = pressures.size();
output_dBdp.resize(num);
for (int i = 0; i < num; ++i) {
output_dBdp[i] = dBdp(0, pressures[i][phase], surfvol[i]); // \TODO Speedup here by using already evaluated B.
}
}
double MiscibilityLiveGas::miscible_gas(double press, const surfvol_t& surfvol, int item,
bool deriv) const
{
int section;
double R = linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[3], press,
section);
double maxR = surfvol[Liquid]/surfvol[Vapour];
if (deriv) {
if (R < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_gas_table_[0],
saturated_gas_table_[item],
press);
} else { // Undersaturated case
int is = section;
if (undersat_gas_tables_[is][0].size() < 2) {
double val = (saturated_gas_table_[item][is+1]
- saturated_gas_table_[item][is]) /
(saturated_gas_table_[0][is+1] -
saturated_gas_table_[0][is]);
return val;
}
double val1 =
linearInterpolationExtrap(undersat_gas_tables_[is][0],
undersat_gas_tables_[is][item],
maxR);
double val2 =
linearInterpolationExtrap(undersat_gas_tables_[is+1][0],
undersat_gas_tables_[is+1][item],
maxR);
double val = (val2 - val1)/
(saturated_gas_table_[0][is+1] - saturated_gas_table_[0][is]);
return val;
}
} else {
if (R < maxR ) { // Saturated case
return linearInterpolationExtrap(saturated_gas_table_[0],
saturated_gas_table_[item],
press);
} else { // Undersaturated case
int is = section;
// Extrapolate from first table section
if (is == 0 && press < saturated_gas_table_[0][0]) {
return linearInterpolationExtrap(undersat_gas_tables_[0][0],
undersat_gas_tables_[0][item],
maxR);
}
// Extrapolate from last table section
int ltp = saturated_gas_table_[0].size() - 1;
if (is+1 == ltp && press > saturated_gas_table_[0][ltp]) {
return linearInterpolationExtrap(undersat_gas_tables_[ltp][0],
undersat_gas_tables_[ltp][item],
maxR);
}
// Interpolate between table sections
double w = (press - saturated_gas_table_[0][is]) /
(saturated_gas_table_[0][is+1] -
saturated_gas_table_[0][is]);
if (undersat_gas_tables_[is][0].size() < 2) {
double val = saturated_gas_table_[item][is] +
w*(saturated_gas_table_[item][is+1] -
saturated_gas_table_[item][is]);
return val;
}
double val1 =
linearInterpolationExtrap(undersat_gas_tables_[is][0],
undersat_gas_tables_[is][item],
maxR);
double val2 =
linearInterpolationExtrap(undersat_gas_tables_[is+1][0],
undersat_gas_tables_[is+1][item],
maxR);
double val = val1 + w*(val2 - val1);
return val;
}
}
}
} // namespace Opm

View File

@ -0,0 +1,92 @@
//===========================================================================
//
// File: MiscibilityLiveGas.hpp
//
// Created: Wed Feb 10 09:21:26 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 SINTEF_MISCIBILITYLIVEGAS_HEADER
#define SINTEF_MISCIBILITYLIVEGAS_HEADER
/** Class for miscible wet gas.
* Detailed description.
*/
#include "MiscibilityProps.hpp"
namespace Opm
{
class MiscibilityLiveGas : public MiscibilityProps
{
public:
typedef std::vector<std::vector<std::vector<double> > > table_t;
MiscibilityLiveGas(const table_t& pvto);
virtual ~MiscibilityLiveGas();
virtual double getViscosity(int region, double press, const surfvol_t& surfvol) const;
virtual double R(int region, double press, const surfvol_t& surfvol) const;
virtual double dRdp(int region, double press, const surfvol_t& surfvol) const;
virtual double B(int region, double press, const surfvol_t& surfvol) const;
virtual double dBdp(int region, double press, const surfvol_t& surfvol) const;
virtual void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const;
virtual void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const;
protected:
// item: 1=B 2=mu;
double miscible_gas(double press, const surfvol_t& surfvol, int item,
bool deriv = false) const;
// PVT properties of wet gas (with vaporised oil)
std::vector<std::vector<double> > saturated_gas_table_;
std::vector<std::vector<std::vector<double> > > undersat_gas_tables_;
};
}
#endif // SINTEF_MISCIBILITYLIVEGAS_HEADER

View File

@ -0,0 +1,395 @@
//===========================================================================
//
// File: MiscibiltyLiveOil.cpp
//
// Created: Wed Feb 10 09:08:25 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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/core/fluid/blackoil/MiscibilityLiveOil.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/linInt.hpp>
#include <algorithm>
using namespace std;
using namespace Dune;
namespace Opm
{
//------------------------------------------------------------------------
// Member functions
//-------------------------------------------------------------------------
/// Constructor
MiscibilityLiveOil::MiscibilityLiveOil(const table_t& pvto)
{
// OIL, PVTO
const int region_number = 0;
if (pvto.size() != 1) {
THROW("More than one PVD-region");
}
saturated_oil_table_.resize(4);
const int sz = pvto[region_number].size();
for (int k=0; k<4; ++k) {
saturated_oil_table_[k].resize(sz);
}
for (int i=0; i<sz; ++i) {
saturated_oil_table_[0][i] = pvto[region_number][i][1]; // p
saturated_oil_table_[1][i] = 1.0/pvto[region_number][i][2]; // 1/Bo
saturated_oil_table_[2][i] = pvto[region_number][i][3]; // mu_o
saturated_oil_table_[3][i] = pvto[region_number][i][0]; // Rs
}
undersat_oil_tables_.resize(sz);
for (int i=0; i<sz; ++i) {
undersat_oil_tables_[i].resize(3);
int tsize = (pvto[region_number][i].size() - 1)/3;
undersat_oil_tables_[i][0].resize(tsize);
undersat_oil_tables_[i][1].resize(tsize);
undersat_oil_tables_[i][2].resize(tsize);
for (int j=0, k=0; j<tsize; ++j) {
undersat_oil_tables_[i][0][j] = pvto[region_number][i][++k]; // p
undersat_oil_tables_[i][1][j] = 1.0/pvto[region_number][i][++k]; // 1/Bo
undersat_oil_tables_[i][2][j] = pvto[region_number][i][++k]; // mu_o
}
}
// Fill in additional entries in undersaturated tables by interpolating/extrapolating 1/Bo and mu_o ...
int iPrev = -1;
int iNext = 1;
while (undersat_oil_tables_[iNext][0].size() < 2) {
++iNext;
}
ASSERT(iNext < sz);
for (int i=0; i<sz; ++i) {
if (undersat_oil_tables_[i][0].size() > 1) {
iPrev = i;
continue;
}
bool flagPrev = (iPrev >= 0);
bool flagNext = true;
if (iNext < i) {
iPrev = iNext;
flagPrev = true;
iNext = i+1;
while (undersat_oil_tables_[iNext][0].size() < 2) {
++iNext;
}
}
double slopePrevBinv = 0.0;
double slopePrevVisc = 0.0;
double slopeNextBinv = 0.0;
double slopeNextVisc = 0.0;
while (flagPrev || flagNext) {
double pressure0 = undersat_oil_tables_[i][0].back();
double pressure = 1.0e47;
if (flagPrev) {
std::vector<double>::iterator itPrev = upper_bound(undersat_oil_tables_[iPrev][0].begin(),
undersat_oil_tables_[iPrev][0].end(),pressure0+1.);
if (itPrev == undersat_oil_tables_[iPrev][0].end()) {
--itPrev; // Extrapolation ...
} else if (itPrev == undersat_oil_tables_[iPrev][0].begin()) {
++itPrev;
}
if (itPrev == undersat_oil_tables_[iPrev][0].end()-1) {
flagPrev = false; // Last data set for "prev" ...
}
double dPPrev = *itPrev - *(itPrev-1);
pressure = *itPrev;
int index = int(itPrev - undersat_oil_tables_[iPrev][0].begin());
slopePrevBinv = (undersat_oil_tables_[iPrev][1][index] - undersat_oil_tables_[iPrev][1][index-1])/dPPrev;
slopePrevVisc = (undersat_oil_tables_[iPrev][2][index] - undersat_oil_tables_[iPrev][2][index-1])/dPPrev;
}
if (flagNext) {
std::vector<double>::iterator itNext = upper_bound(undersat_oil_tables_[iNext][0].begin(),
undersat_oil_tables_[iNext][0].end(),pressure0+1.);
if (itNext == undersat_oil_tables_[iNext][0].end()) {
--itNext; // Extrapolation ...
} else if (itNext == undersat_oil_tables_[iNext][0].begin()) {
++itNext;
}
if (itNext == undersat_oil_tables_[iNext][0].end()-1) {
flagNext = false; // Last data set for "next" ...
}
double dPNext = *itNext - *(itNext-1);
if (flagPrev) {
pressure = std::min(pressure,*itNext);
} else {
pressure = *itNext;
}
int index = int(itNext - undersat_oil_tables_[iNext][0].begin());
slopeNextBinv = (undersat_oil_tables_[iNext][1][index] - undersat_oil_tables_[iNext][1][index-1])/dPNext;
slopeNextVisc = (undersat_oil_tables_[iNext][2][index] - undersat_oil_tables_[iNext][2][index-1])/dPNext;
}
double dP = pressure - pressure0;
if (iPrev >= 0) {
double w = (saturated_oil_table_[3][i] - saturated_oil_table_[3][iPrev]) /
(saturated_oil_table_[3][iNext] - saturated_oil_table_[3][iPrev]);
undersat_oil_tables_[i][0].push_back(pressure0+dP);
undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back() +
dP*(slopePrevBinv+w*(slopeNextBinv-slopePrevBinv)));
undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back() +
dP*(slopePrevVisc+w*(slopeNextVisc-slopePrevVisc)));
} else {
undersat_oil_tables_[i][0].push_back(pressure0+dP);
undersat_oil_tables_[i][1].push_back(undersat_oil_tables_[i][1].back()+dP*slopeNextBinv);
undersat_oil_tables_[i][2].push_back(undersat_oil_tables_[i][2].back()+dP*slopeNextVisc);
}
}
}
}
// Destructor
MiscibilityLiveOil::~MiscibilityLiveOil()
{
}
double MiscibilityLiveOil::getViscosity(int /*region*/, double press, const surfvol_t& surfvol) const
{
return miscible_oil(press, surfvol, 2, false);
}
void MiscibilityLiveOil::getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output[i] = miscible_oil(pressures[i][phase], surfvol[i], 2, false);
}
}
// Dissolved gas-oil ratio
double MiscibilityLiveOil::R(int /*region*/, double press, const surfvol_t& surfvol) const
{
return evalR(press, surfvol);
}
void MiscibilityLiveOil::R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output[i] = evalR(pressures[i][phase], surfvol[i]);
}
}
// Dissolved gas-oil ratio derivative
double MiscibilityLiveOil::dRdp(int /*region*/, double press, const surfvol_t& surfvol) const
{
double R = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], press);
double maxR = surfvol[Vapour]/surfvol[Liquid];
if (R < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_oil_table_[0],
saturated_oil_table_[3],
press);
} else {
return 0.0; // Undersaturated case
}
}
void MiscibilityLiveOil::dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output_R.resize(num);
output_dRdp.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
evalRDeriv(pressures[i][phase], surfvol[i], output_R[i], output_dRdp[i]);
}
}
double MiscibilityLiveOil::B(int /*region*/, double press, const surfvol_t& surfvol) const
{
return evalB(press, surfvol);
}
void MiscibilityLiveOil::B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const
{
ASSERT(pressures.size() == surfvol.size());
int num = pressures.size();
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output[i] = evalB(pressures[i][phase], surfvol[i]);
}
}
double MiscibilityLiveOil::dBdp(int /*region*/, double press, const surfvol_t& surfvol) const
{
// if (surfvol[Liquid] == 0.0) return 0.0; // To handle no-oil case.
double Bo = evalB(press, surfvol); // \TODO check if we incur virtual call overhead here.
return -Bo*Bo*miscible_oil(press, surfvol, 1, true);
}
void MiscibilityLiveOil::dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const
{
ASSERT(pressures.size() == surfvol.size());
B(pressures, surfvol, phase, output_B);
int num = pressures.size();
output_dBdp.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output_dBdp[i] = dBdp(0, pressures[i][phase], surfvol[i]); // \TODO Speedup here by using already evaluated B.
}
}
double MiscibilityLiveOil::evalR(double press, const surfvol_t& surfvol) const
{
if (surfvol[Vapour] == 0.0) {
return 0.0;
}
double R = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], press);
double maxR = surfvol[Vapour]/surfvol[Liquid];
if (R < maxR ) { // Saturated case
return R;
} else {
return maxR; // Undersaturated case
}
}
void MiscibilityLiveOil::evalRDeriv(const double press, const surfvol_t& surfvol,
double& R, double& dRdp) const
{
if (surfvol[Vapour] == 0.0) {
R = 0.0;
dRdp = 0.0;
return;
}
R = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3], press);
double maxR = surfvol[Vapour]/surfvol[Liquid];
if (R < maxR ) {
// Saturated case
dRdp = linearInterpolDerivative(saturated_oil_table_[0],
saturated_oil_table_[3],
press);
} else {
// Undersaturated case
R = maxR;
dRdp = 0.0;
}
}
double MiscibilityLiveOil::evalB(double press, const surfvol_t& surfvol) const
{
// if (surfvol[Liquid] == 0.0) return 1.0; // To handle no-oil case.
return 1.0/miscible_oil(press, surfvol, 1, false);
}
void MiscibilityLiveOil::evalBDeriv(const double press, const surfvol_t& surfvol,
double& B, double& dBdp) const
{
B = evalB(press, surfvol);
dBdp = -B*B*miscible_oil(press, surfvol, 1, true);
}
double MiscibilityLiveOil::miscible_oil(double press, const surfvol_t& surfvol,
int item, bool deriv) const
{
int section;
double R = linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[3],
press, section);
double maxR = (surfvol[Liquid] == 0.0) ? 0.0 : surfvol[Vapour]/surfvol[Liquid];
if (deriv) {
if (R < maxR ) { // Saturated case
return linearInterpolDerivative(saturated_oil_table_[0],
saturated_oil_table_[item],
press);
} else { // Undersaturated case
int is = tableIndex(saturated_oil_table_[3], maxR);
double w = (maxR - saturated_oil_table_[3][is]) /
(saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
ASSERT(undersat_oil_tables_[is][0].size() >= 2);
ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
double val1 =
linearInterpolDerivative(undersat_oil_tables_[is][0],
undersat_oil_tables_[is][item],
press);
double val2 =
linearInterpolDerivative(undersat_oil_tables_[is+1][0],
undersat_oil_tables_[is+1][item],
press);
double val = val1 + w*(val2 - val1);
return val;
}
} else {
if (R < maxR ) { // Saturated case
return linearInterpolationExtrap(saturated_oil_table_[0],
saturated_oil_table_[item],
press);
} else { // Undersaturated case
// Interpolate between table sections
int is = tableIndex(saturated_oil_table_[3], maxR);
double w = (maxR - saturated_oil_table_[3][is]) /
(saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
ASSERT(undersat_oil_tables_[is][0].size() >= 2);
ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
double val1 =
linearInterpolationExtrap(undersat_oil_tables_[is][0],
undersat_oil_tables_[is][item],
press);
double val2 =
linearInterpolationExtrap(undersat_oil_tables_[is+1][0],
undersat_oil_tables_[is+1][item],
press);
double val = val1 + w*(val2 - val1);
return val;
}
}
}
} // namespace Opm

View File

@ -0,0 +1,97 @@
//===========================================================================
//
// File: MiscibilityLiveOil.hpp
//
// Created: Wed Feb 10 09:08:09 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 SINTEF_MISCIBILITYLIVEOIL_HEADER
#define SINTEF_MISCIBILITYLIVEOIL_HEADER
/** Class for miscible live oil.
* Detailed description.
*/
#include "MiscibilityProps.hpp"
namespace Opm
{
class MiscibilityLiveOil : public MiscibilityProps
{
public:
typedef std::vector<std::vector<std::vector<double> > > table_t;
MiscibilityLiveOil(const table_t& pvto);
virtual ~MiscibilityLiveOil();
virtual double getViscosity(int region, double press, const surfvol_t& surfvol) const;
virtual double R (int region, double press, const surfvol_t& surfvol) const;
virtual double dRdp(int region, double press, const surfvol_t& surfvol) const;
virtual double B (int region, double press, const surfvol_t& surfvol) const;
virtual double dBdp(int region, double press, const surfvol_t& surfvol) const;
virtual void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const;
virtual void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const;
virtual void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const;
protected:
double evalR(double press, const surfvol_t& surfvol) const;
void evalRDeriv(double press, const surfvol_t& surfvol, double& R, double& dRdp) const;
double evalB(double press, const surfvol_t& surfvol) const;
void evalBDeriv(double press, const surfvol_t& surfvol, double& B, double& dBdp) const;
// item: 1=B 2=mu;
double miscible_oil(double press, const surfvol_t& surfvol, int item,
bool deriv = false) const;
// PVT properties of live oil (with dissolved gas)
std::vector<std::vector<double> > saturated_oil_table_;
std::vector<std::vector<std::vector<double> > > undersat_oil_tables_;
};
}
#endif // SINTEF_MISCIBILITYLIVEOIL_HEADER

View File

@ -0,0 +1,52 @@
//===========================================================================
//
// File: MiscibilityProps.cpp
//
// Created: Wed Feb 10 09:05:05 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "MiscibilityProps.hpp"
using namespace std;
namespace Opm
{
//------------------------------------------------------------------------
// Member functions
//-------------------------------------------------------------------------
/// Constructor
MiscibilityProps::MiscibilityProps()
{
}
MiscibilityProps::~MiscibilityProps()
{
}
} // namespace Opm

View File

@ -0,0 +1,87 @@
//===========================================================================
//
// File: MiscibilityProps.hpp
//
// Created: Wed Feb 10 09:04:35 2010
//
// Author: Bjørn Spjelkavik <bsp@sintef.no>
//
// Revision: $Id$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 SINTEF_MISCIBILITYPROPS_HEADER
#define SINTEF_MISCIBILITYPROPS_HEADER
/** Base class for properties of fluids and rocks.
* Detailed description.
*/
#include "BlackoilDefs.hpp"
#include <vector>
#include <tr1/array>
namespace Opm
{
class MiscibilityProps : public BlackoilDefs
{
public:
typedef CompVec surfvol_t;
MiscibilityProps();
virtual ~MiscibilityProps();
virtual double getViscosity(int region, double press, const surfvol_t& surfvol) const = 0;
virtual double B (int region, double press, const surfvol_t& surfvol) const = 0;
virtual double dBdp(int region, double press, const surfvol_t& surfvol) const = 0;
virtual double R (int region, double press, const surfvol_t& surfvol) const = 0;
virtual double dRdp(int region, double press, const surfvol_t& surfvol) const = 0;
virtual void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const = 0;
virtual void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const = 0;
virtual void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const = 0;
virtual void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output) const = 0;
virtual void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvol,
int phase,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const = 0;
};
} // namespace Opm
#endif // SINTEF_MISCIBILITYPROPS_HEADER

View File

@ -0,0 +1,194 @@
//===========================================================================
//
// File: MiscibilityWater.hpp
//
// Created: Tue May 18 10:26:13 2010
//
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
// Bjørn Spjelkavik <bsp@sintef.no>
//
// $Date$
//
// $Revision$
//
//===========================================================================
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 OPENRS_MISCIBILITYWATER_HEADER
#define OPENRS_MISCIBILITYWATER_HEADER
#include <opm/core/fluid/blackoil/MiscibilityProps.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
// Forward declaration.
class PVTW;
namespace Opm
{
class MiscibilityWater : public MiscibilityProps
{
public:
typedef std::vector<std::vector<double> > table_t;
MiscibilityWater(const table_t& pvtw)
{
const int region_number = 0;
if (pvtw.size() != 1) {
THROW("More than one PVD-region");
}
ref_press_ = pvtw[region_number][0];
ref_B_ = pvtw[region_number][1];
comp_ = pvtw[region_number][2];
viscosity_ = pvtw[region_number][3];
if (pvtw[region_number].size() > 4 && pvtw[region_number][4] != 0.0) {
THROW("MiscibilityWater does not support 'viscosibility'.");
}
}
MiscibilityWater(double visc)
: ref_press_(0.0),
ref_B_(1.0),
comp_(0.0),
viscosity_(visc)
{
}
virtual ~MiscibilityWater()
{
}
virtual double getViscosity(int /*region*/, double /*press*/, const surfvol_t& /*surfvol*/) const
{
return viscosity_;
}
virtual void getViscosity(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int,
std::vector<double>& output) const
{
int num = pressures.size();
output.clear();
output.resize(num, viscosity_);
}
virtual double B(int /*region*/, double press, const surfvol_t& /*surfvol*/) const
{
if (comp_) {
// Computing a polynomial approximation to the exponential.
double x = comp_*(press - ref_press_);
return ref_B_/(1.0 + x + 0.5*x*x);
} else {
return ref_B_;
}
}
virtual void B(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int phase,
std::vector<double>& output) const
{
int num = pressures.size();
if (comp_) {
output.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
// Computing a polynomial approximation to the exponential.
double x = comp_*(pressures[i][phase] - ref_press_);
output[i] = ref_B_/(1.0 + x + 0.5*x*x);
}
} else {
output.clear();
output.resize(num, ref_B_);
}
}
virtual double dBdp(int region, double press, const surfvol_t& surfvol) const
{
if (comp_) {
return -comp_*B(region, press, surfvol);
} else {
return 0.0;
}
}
virtual void dBdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>& surfvols,
int phase,
std::vector<double>& output_B,
std::vector<double>& output_dBdp) const
{
B(pressures, surfvols, phase, output_B);
int num = pressures.size();
if (comp_) {
output_dBdp.resize(num);
#pragma omp parallel for
for (int i = 0; i < num; ++i) {
output_dBdp[i] = -comp_*output_B[i];
}
} else {
output_dBdp.clear();
output_dBdp.resize(num, 0.0);
}
}
virtual double R(int /*region*/, double /*press*/, const surfvol_t& /*surfvol*/) const
{
return 0.0;
}
virtual void R(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int,
std::vector<double>& output) const
{
int num = pressures.size();
output.clear();
output.resize(num, 0.0);
}
virtual double dRdp(int /*region*/, double /*press*/, const surfvol_t& /*surfvol*/) const
{
return 0.0;
}
virtual void dRdp(const std::vector<PhaseVec>& pressures,
const std::vector<CompVec>&,
int,
std::vector<double>& output_R,
std::vector<double>& output_dRdp) const
{
int num = pressures.size();
output_R.clear();
output_R.resize(num, 0.0);
output_dRdp.clear();
output_dRdp.resize(num, 0.0);
}
private:
double ref_press_;
double ref_B_;
double comp_;
double viscosity_;
};
}
#endif // OPENRS_MISCIBILITYWATER_HEADER

View File

@ -0,0 +1,260 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_UNIFORMTABLELINEAR_HEADER_INCLUDED
#define OPM_UNIFORMTABLELINEAR_HEADER_INCLUDED
#include <cmath>
#include <exception>
#include <vector>
#include <utility>
#include <iostream>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/linearInterpolation.hpp>
namespace Dune {
namespace utils {
/// @brief This class uses linear interpolation to compute the value
/// (and its derivative) of a function f sampled at uniform points.
/// @tparam T the range type of the function (should be an algebraic ring type)
template<typename T>
class UniformTableLinear
{
public:
/// @brief Default constructor.
UniformTableLinear();
/// @brief Construct from vector of y-values.
/// @param xmin the x value corresponding to the first y value.
/// @param xmax the x value corresponding to the last y value.
/// @param y_values vector of range values.
UniformTableLinear(double xmin,
double xmax,
const std::vector<T>& y_values);
/// @brief Construct from array of y-values.
/// @param xmin the x value corresponding to the first y value.
/// @param xmax the x value corresponding to the last y value.
/// @param y_values array of range values.
/// @param num_y_values the number of values in y_values.
UniformTableLinear(double xmin,
double xmax,
const T* y_values,
int num_y_values);
/// @brief Get the domain.
/// @return the domain as a pair of doubles.
std::pair<double, double> domain();
/// @brief Rescale the domain.
/// @param new_domain the new domain as a pair of doubles.
void rescaleDomain(std::pair<double, double> new_domain);
/// @brief Evaluate the value at x.
/// @param x a domain value
/// @return f(x)
double operator()(const double x) const;
/// @brief Evaluate the derivative at x.
/// @param x a domain value
/// @return f'(x)
double derivative(const double x) const;
/// @brief Equality operator.
/// @param other another UniformTableLinear.
/// @return true if they are represented exactly alike.
bool operator==(const UniformTableLinear& other) const;
/// @brief Policies for how to behave when trying to evaluate outside the domain.
enum RangePolicy {Throw = 0, ClosestValue = 1, Extrapolate = 2};
/// @brief Sets the behavioural policy for evaluation to the left of the domain.
/// @param rp the policy
void setLeftPolicy(RangePolicy rp);
/// @brief Sets the behavioural policy for evaluation to the right of the domain.
/// @param rp the policy
void setRightPolicy(RangePolicy rp);
protected:
double xmin_;
double xmax_;
double xdelta_;
std::vector<T> y_values_;
RangePolicy left_;
RangePolicy right_;
template <typename U>
friend std::ostream& operator<<(std::ostream& os, const UniformTableLinear<U>& t);
};
// Member implementations.
template<typename T>
inline
UniformTableLinear<T>
::UniformTableLinear()
: left_(ClosestValue), right_(ClosestValue)
{
}
template<typename T>
inline
UniformTableLinear<T>
::UniformTableLinear(double xmin,
double xmax,
const std::vector<T>& y_values)
: xmin_(xmin), xmax_(xmax), y_values_(y_values),
left_(ClosestValue), right_(ClosestValue)
{
ASSERT(xmax > xmin);
ASSERT(y_values.size() > 1);
xdelta_ = (xmax - xmin)/(y_values.size() - 1);
}
template<typename T>
inline
UniformTableLinear<T>
::UniformTableLinear(double xmin,
double xmax,
const T* y_values,
int num_y_values)
: xmin_(xmin), xmax_(xmax),
y_values_(y_values, y_values + num_y_values),
left_(ClosestValue), right_(ClosestValue)
{
ASSERT(xmax > xmin);
ASSERT(y_values_.size() > 1);
xdelta_ = (xmax - xmin)/(y_values_.size() - 1);
}
template<typename T>
inline std::pair<double, double>
UniformTableLinear<T>
::domain()
{
return std::make_pair(xmin_, xmax_);
}
template<typename T>
inline void
UniformTableLinear<T>
::rescaleDomain(std::pair<double, double> new_domain)
{
xmin_ = new_domain.first;
xmax_ = new_domain.second;
xdelta_ = (xmax_ - xmin_)/(y_values_.size() - 1);
}
template<typename T>
inline double
UniformTableLinear<T>
::operator()(const double xparam) const
{
// Implements ClosestValue policy.
double x = std::min(xparam, xmax_);
x = std::max(x, xmin_);
// Lookup is easy since we are uniform in x.
double pos = (x - xmin_)/xdelta_;
double posi = std::floor(pos);
int left = int(posi);
if (left == int(y_values_.size()) - 1) {
// We are at xmax_
return y_values_.back();
}
double w = pos - posi;
return (1.0 - w)*y_values_[left] + w*y_values_[left + 1];
}
template<typename T>
inline double
UniformTableLinear<T>
::derivative(const double xparam) const
{
// Implements ClosestValue policy.
double x = std::min(xparam, xmax_);
x = std::max(x, xmin_);
// Lookup is easy since we are uniform in x.
double pos = (x - xmin_)/xdelta_;
double posi = std::floor(pos);
int left = int(posi);
if (left == int(y_values_.size()) - 1) {
// We are at xmax_
--left;
}
return (y_values_[left + 1] - y_values_[left])/xdelta_;
}
template<typename T>
inline bool
UniformTableLinear<T>
::operator==(const UniformTableLinear<T>& other) const
{
return xmin_ == other.xmin_
&& xdelta_ == other.xdelta_
&& y_values_ == other.y_values_
&& left_ == other.left_
&& right_ == other.right_;
}
template<typename T>
inline void
UniformTableLinear<T>
::setLeftPolicy(RangePolicy rp)
{
if (rp != ClosestValue) {
THROW("Only ClosestValue RangePolicy implemented.");
}
left_ = rp;
}
template<typename T>
inline void
UniformTableLinear<T>
::setRightPolicy(RangePolicy rp)
{
if (rp != ClosestValue) {
THROW("Only ClosestValue RangePolicy implemented.");
}
right_ = rp;
}
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const UniformTableLinear<T>& t)
{
int n = t.y_values_.size();
for (int i = 0; i < n; ++i) {
double f = double(i)/double(n - 1);
os << (1.0 - f)*t.xmin_ + f*t.xmax_
<< " " << t.y_values_[i] << '\n';
}
return os;
}
} // namespace utils
} // namespace Dune
#endif // OPM_UNIFORMTABLELINEAR_HEADER_INCLUDED

View File

@ -0,0 +1,52 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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_BUILDUNIFORMMONOTONETABLE_HEADER_INCLUDED
#define OPM_BUILDUNIFORMMONOTONETABLE_HEADER_INCLUDED
#include <opm/core/utility/MonotCubicInterpolator.hpp>
#include <opm/core/utility/UniformTableLinear.hpp>
namespace Dune {
namespace utils {
template <typename T>
void buildUniformMonotoneTable(const std::vector<double>& xv,
const std::vector<T>& yv,
const int samples,
UniformTableLinear<T>& table)
{
MonotCubicInterpolator interp(xv, yv);
std::vector<T> uniform_yv(samples);
double xmin = xv[0];
double xmax = xv.back();
for (int i = 0; i < samples; ++i) {
double w = double(i)/double(samples - 1);
double x = (1.0 - w)*xmin + w*xmax;
uniform_yv[i] = interp(x);
}
table = UniformTableLinear<T>(xmin, xmax, uniform_yv);
}
} // namespace utils
} // namespace Dune
#endif // OPM_BUILDUNIFORMMONOTONETABLE_HEADER_INCLUDED

View File

@ -0,0 +1,90 @@
//===========================================================================
//
// File: linearInterpolation.hpp
//
// Created: Tue Sep 9 12:49:39 2008
//
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
//
// $Date$
//
// $Revision$
//
//===========================================================================
/*
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
Copyright 2009, 2010 Statoil ASA.
This file is part of The Open Reservoir Simulator Project (OpenRS).
OpenRS 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.
OpenRS 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 OpenRS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPENRS_LINEARINTERPOLATION_HEADER
#define OPENRS_LINEARINTERPOLATION_HEADER
#include <vector>
#include <algorithm>
namespace Dune
{
/** Linear interpolation.
* Given an increasing vector xv of parameter values and
* a vector yv of point values of the same size,
* the function returns ...
*/
template <typename T>
T linearInterpolation(const std::vector<double>& xv,
const std::vector<T>& yv,
double x)
{
std::vector<double>::const_iterator lb = std::lower_bound(xv.begin(), xv.end(), x);
int lb_ix = lb - xv.begin();
if (lb_ix == 0) {
return yv[0];
} else if (lb_ix == int(xv.size())) {
return yv.back();
} else {
double w = (x - xv[lb_ix - 1])/(xv[lb_ix] - xv[lb_ix - 1]);
return (1.0 - w)*yv[lb_ix - 1] + w*yv[lb_ix];
}
}
/// @brief
/// @todo Doc me!
/// @tparam
/// @param
/// @return
template <typename T>
T linearInterpolationDerivative(const std::vector<double>& xv,
const std::vector<T>& yv,
double x)
{
double epsilon = 1e-4; // @@ Ad hoc, should choose based on xv.
double x_low = std::max(xv[0], x - epsilon);
double x_high = std::min(xv.back(), x + epsilon);
T low = linearInterpolation(xv, yv, x_low);
T high = linearInterpolation(xv, yv, x_high);
return (high - low)/(x_high - x_low);
}
} // namespace Dune
#endif // OPENRS_LINEARINTERPOLATION_HEADER

View File

@ -5,16 +5,13 @@ $(BOOST_CPPFLAGS)
LDFLAGS = $(BOOST_LDFLAGS)
LDADD = \
$(top_builddir)/libopmcore.la \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \
$(BOOST_DATE_TIME_LIB) \
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS)
LDADD = $(top_builddir)/libopmcore.la
noinst_PROGRAMS = \
bo_fluid_p_and_z_deps \
bo_fluid_pressuredeps \
bo_fluid_test \
monotcubicinterpolator_test \
param_test \
sparsetable_test \
@ -23,6 +20,9 @@ unit_test \
test_readvector \
test_sf2p
bo_fluid_p_and_z_deps_SOURCES = bo_fluid_p_and_z_deps.cpp
bo_fluid_pressuredeps_SOURCES = bo_fluid_pressuredeps.cpp
bo_fluid_test_SOURCES = bo_fluid_test.cpp
monotcubicinterpolator_test_SOURCES = monotcubicinterpolator_test.cpp
param_test_SOURCES = param_test.cpp
sparsetable_test_SOURCES = sparsetable_test.cpp

View File

@ -0,0 +1,132 @@
/*
Copyright 2011 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/fluid/BlackoilFluid.hpp>
int main(int argc, char** argv)
{
std::cout << "%{\n";
// Parameters.
Dune::parameter::ParameterGroup param(argc, argv);
// Parser.
std::string ecl_file = param.get<std::string>("filename");
Dune::EclipseGridParser parser(ecl_file);
// Look at the BlackoilFluid behaviour
Opm::BlackoilFluid fluid;
fluid.init(parser);
Opm::BlackoilFluid::CompVec z0(0.0);
z0[Opm::BlackoilFluid::Water] = param.getDefault("z_w", 0.0);
z0[Opm::BlackoilFluid::Oil] = param.getDefault("z_o", 1.0);
z0[Opm::BlackoilFluid::Gas] = param.getDefault("z_g", 0.0);
int num_pts_p = param.getDefault("num_pts_p", 41);
int num_pts_z = param.getDefault("num_pts_z", 51);
double min_press = param.getDefault("min_press", 1e7);
double max_press = param.getDefault("max_press", 3e7);
int changing_component = param.getDefault("changing_component", int(Opm::BlackoilFluid::Gas));
double min_z = param.getDefault("min_z", 0.0);
double max_z = param.getDefault("max_z", 500.0);
#ifdef COMPUTE_OLD_TERMS
int variable = param.getDefault("variable", 0);
#else
int variable = param.getDefault("variable", 2);
#endif
Opm::BlackoilFluid::CompVec z = z0;
std::cout << "%}\n"
<< "data = [\n";
for (int i = 0; i < num_pts_p; ++i) {
double pfactor = num_pts_p < 2 ? 0.0 : double(i)/double(num_pts_p - 1);
double p = (1.0 - pfactor)*min_press + pfactor*max_press;
for (int j = 0; j < num_pts_z; ++j) {
double zfactor = num_pts_z < 2 ? 0.0 : double(j)/double(num_pts_z - 1);
z[changing_component] = (1.0 - zfactor)*min_z + zfactor*max_z;
// std::cout << p << ' ' << z << '\n';
Opm::BlackoilFluid::FluidState state = fluid.computeState(Opm::BlackoilFluid::PhaseVec(p), z);
std::cout.precision(6);
std::cout.width(15);
std::cout.fill(' ');
double var = 0.0;
switch (variable) {
#ifdef COMPUTE_OLD_TERMS
case 0:
var = state.total_compressibility_;
break;
case 1:
var = state.experimental_term_;
break;
#endif
case 2:
var = state.saturation_[0];
break;
case 3:
var = state.saturation_[1];
break;
case 4:
var = state.saturation_[2];
break;
case 5:
var = state.formation_volume_factor_[0];
break;
case 6:
var = state.formation_volume_factor_[1];
break;
case 7:
var = state.formation_volume_factor_[2];
break;
case 8:
var = state.solution_factor_[0];
break;
case 9:
var = state.solution_factor_[1];
break;
case 10:
var = state.solution_factor_[2];
break;
default:
THROW("Unknown varable specification: " << variable);
break;
}
std::cout << var << ' ';
}
std::cout << '\n';
}
std::cout << "];\n\n"
<< "paxis = [\n";
for (int i = 0; i < num_pts_p; ++i) {
double pfactor = double(i)/double(num_pts_p - 1);
double p = (1.0 - pfactor)*min_press + pfactor*max_press;
std::cout << p << '\n';
}
std::cout << "];\n\n"
<< "zaxis = [\n";
for (int j = 0; j < num_pts_z; ++j) {
double zfactor = double(j)/double(num_pts_z - 1);
std::cout << (1.0 - zfactor)*min_z + zfactor*max_z << '\n';
}
std::cout << "];\n";
}

View File

@ -0,0 +1,108 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/fluid/BlackoilFluid.hpp>
#ifdef COMPUTE_OLD_TERMS
void printCompressibilityTerms(double p, const Opm::BlackoilFluid::FluidState& state)
{
std::cout.precision(6);
std::cout.width(15);
std::cout.fill(' ');
std::cout << p << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.total_compressibility_ << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << totmob << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.total_phase_volume_density_ << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.experimental_term_ << '\n';
}
#endif
void printSatsEtc(double p, const Opm::BlackoilFluid::FluidState& state)
{
std::cout.precision(6);
std::cout.width(15);
std::cout.fill(' ');
std::cout << p << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.saturation_[0] << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.saturation_[1] << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.saturation_[2] << " ";
std::cout.width(15);
std::cout.fill(' ');
std::cout << state.total_phase_volume_density_ << '\n';
}
int main(int argc, char** argv)
{
// Parameters.
Dune::parameter::ParameterGroup param(argc, argv);
// Parser.
std::string ecl_file = param.get<std::string>("filename");
Dune::EclipseGridParser parser(ecl_file);
// Look at the BlackoilFluid behaviour
Opm::BlackoilFluid fluid;
fluid.init(parser);
Opm::BlackoilFluid::CompVec z(0.0);
z[Opm::BlackoilFluid::Water] = param.getDefault("z_w", 0.0);
z[Opm::BlackoilFluid::Oil] = param.getDefault("z_o", 1.0);
z[Opm::BlackoilFluid::Gas] = param.getDefault("z_g", 0.0);
int num_pts = param.getDefault("num_pts", 41);
double min_press = param.getDefault("min_press", 1e7);
double max_press = param.getDefault("max_press", 3e7);
#ifdef COMPUTE_OLD_TERMS
bool print_compr = param.getDefault("print_compr", true);
#endif
for (int i = 0; i < num_pts; ++i) {
double factor = double(i)/double(num_pts - 1);
double p = (1.0 - factor)*min_press + factor*max_press;
Opm::BlackoilFluid::FluidState state = fluid.computeState(Opm::BlackoilFluid::PhaseVec(p), z);
double totmob = 0.0;
for (int phase = 0; phase < Opm::BlackoilFluid::numPhases; ++phase) {
totmob += state.mobility_[phase];
}
#ifdef COMPUTE_OLD_TERMS
if (print_compr) {
printCompressibilityTerms(p, state);
} else {
printSatsEtc(p, state);
}
#else
printSatsEtc(p, state);
#endif
}
}

53
tests/bo_fluid_test.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
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 "config.h"
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/fluid/blackoil/FluidMatrixInteractionBlackoil.hpp>
int main(int argc, char** argv)
{
// Parameters.
Dune::parameter::ParameterGroup param(argc, argv);
// Parser.
std::string ecl_file = param.get<std::string>("filename");
Dune::EclipseGridParser parser(ecl_file);
// Test the FluidMatrixInteractionBlackoil class.
Opm::FluidMatrixInteractionBlackoilParams<double> fluid_params;
fluid_params.init(parser);
typedef Opm::FluidMatrixInteractionBlackoil<double> Law;
Law::PhaseVec s, kr;
const double temp = 300; // [K]
int num = 41;
for (int i = 0; i < num; ++i) {
s[Law::Aqua] = 0.0;
s[Law::Liquid] = double(i)/double(num - 1);
s[Law::Vapour] = 1.0 - s[Law::Aqua] - s[Law::Liquid];
Law::kr(kr, fluid_params, s, temp);
std::cout.width(6);
std::cout.fill(' ');
std::cout << s[Law::Liquid] << " " << kr[0] << ' ' << kr[1] << ' ' << kr[2] << '\n';
}
}