mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-11-27 19:50:16 -06:00
Some adjustments to equil initialisation.
- Saturations, phase pressures, and standard initialsation of RS and RV now agree to baseline. - Tables of RS and RV versus vertical depth (kw RSVD RVVD) have been hardcoded for testing (need new parser) and the calculations agree to baseline in the gas and oil zones. In the water zone there is some differences: Our code computes saturated RS and RV using the final phase pressures (these are modified to be consistent with saturations and capillary pressures) while the baseline uses unmodified phase pressures.
This commit is contained in:
parent
ad285d452c
commit
a2cd03197c
@ -175,7 +175,8 @@ namespace Opm
|
|||||||
* depth and pressure @c press.
|
* depth and pressure @c press.
|
||||||
*/
|
*/
|
||||||
virtual double operator()(const double depth,
|
virtual double operator()(const double depth,
|
||||||
const double press) const = 0;
|
const double press,
|
||||||
|
const double sat = 0.0) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -199,7 +200,8 @@ namespace Opm
|
|||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
operator()(const double /* depth */,
|
operator()(const double /* depth */,
|
||||||
const double /* press */) const
|
const double /* press */,
|
||||||
|
const double sat = 0.0) const
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
@ -216,14 +218,24 @@ namespace Opm
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
* \param[in] props property object
|
||||||
|
* \param[in] cell any cell in the pvt region
|
||||||
* \param[in] depth Depth nodes.
|
* \param[in] depth Depth nodes.
|
||||||
* \param[in] rs Dissolved gas-oil ratio at @c depth.
|
* \param[in] rs Dissolved gas-oil ratio at @c depth.
|
||||||
*/
|
*/
|
||||||
RsVD(const std::vector<double>& depth,
|
RsVD(const BlackoilPropertiesInterface& props,
|
||||||
|
const int cell,
|
||||||
|
const std::vector<double>& depth,
|
||||||
const std::vector<double>& rs)
|
const std::vector<double>& rs)
|
||||||
: depth_(depth)
|
: props_(props)
|
||||||
|
, cell_(cell)
|
||||||
|
, depth_(depth)
|
||||||
, rs_(rs)
|
, rs_(rs)
|
||||||
{
|
{
|
||||||
|
auto pu = props_.phaseUsage();
|
||||||
|
std::fill(z_, z_ + BlackoilPhases::MaxNumPhases, 0.0);
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Vapour]] = 1e100;
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,14 +252,111 @@ namespace Opm
|
|||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
operator()(const double depth,
|
operator()(const double depth,
|
||||||
const double /* press */) const
|
const double press,
|
||||||
|
const double sat_gas = 0.0) const
|
||||||
{
|
{
|
||||||
return linearInterpolation(depth_, rs_, depth);
|
if (sat_gas > 0.0) {
|
||||||
|
return satRs(press);
|
||||||
|
} else {
|
||||||
|
return std::min(satRs(press), linearInterpolation(depth_, rs_, depth));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const BlackoilPropertiesInterface& props_;
|
||||||
|
const int cell_;
|
||||||
std::vector<double> depth_; /**< Depth nodes */
|
std::vector<double> depth_; /**< Depth nodes */
|
||||||
std::vector<double> rs_; /**< Dissolved gas-oil ratio */
|
std::vector<double> rs_; /**< Dissolved gas-oil ratio */
|
||||||
|
double z_[BlackoilPhases::MaxNumPhases];
|
||||||
|
mutable double A_[BlackoilPhases::MaxNumPhases * BlackoilPhases::MaxNumPhases];
|
||||||
|
|
||||||
|
double satRs(const double press) const
|
||||||
|
{
|
||||||
|
props_.matrix(1, &press, z_, &cell_, A_, 0);
|
||||||
|
// Rs/Bo is in the gas row and oil column of A_.
|
||||||
|
// 1/Bo is in the oil row and column.
|
||||||
|
// Recall also that it is stored in column-major order.
|
||||||
|
const int opos = props_.phaseUsage().phase_pos[BlackoilPhases::Liquid];
|
||||||
|
const int gpos = props_.phaseUsage().phase_pos[BlackoilPhases::Vapour];
|
||||||
|
const int np = props_.numPhases();
|
||||||
|
return A_[np*opos + gpos] / A_[np*opos + opos];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type that implements "vaporized oil-gas ratio"
|
||||||
|
* tabulated as a function of depth policy. Data
|
||||||
|
* typically taken from keyword 'RVVD'.
|
||||||
|
*/
|
||||||
|
class RvVD : public RsFunction {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* \param[in] props property object
|
||||||
|
* \param[in] cell any cell in the pvt region
|
||||||
|
* \param[in] depth Depth nodes.
|
||||||
|
* \param[in] rv Dissolved gas-oil ratio at @c depth.
|
||||||
|
*/
|
||||||
|
RvVD(const BlackoilPropertiesInterface& props,
|
||||||
|
const int cell,
|
||||||
|
const std::vector<double>& depth,
|
||||||
|
const std::vector<double>& rv)
|
||||||
|
: props_(props)
|
||||||
|
, cell_(cell)
|
||||||
|
, depth_(depth)
|
||||||
|
, rv_(rv)
|
||||||
|
{
|
||||||
|
auto pu = props_.phaseUsage();
|
||||||
|
std::fill(z_, z_ + BlackoilPhases::MaxNumPhases, 0.0);
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Liquid]] = 1e100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function call.
|
||||||
|
*
|
||||||
|
* \param[in] depth Depth at which to calculate RV
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* \param[in] press Pressure at which to calculate RV
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* \return Vaporized oil-gas ratio (RV) at depth @c
|
||||||
|
* depth and pressure @c press.
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
operator()(const double depth,
|
||||||
|
const double press,
|
||||||
|
const double sat_oil = 0.0 ) const
|
||||||
|
{
|
||||||
|
if (sat_oil > 0.0) {
|
||||||
|
return satRv(press);
|
||||||
|
} else {
|
||||||
|
return std::min(satRv(press), linearInterpolation(depth_, rv_, depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BlackoilPropertiesInterface& props_;
|
||||||
|
const int cell_;
|
||||||
|
std::vector<double> depth_; /**< Depth nodes */
|
||||||
|
std::vector<double> rv_; /**< Vaporized oil-gas ratio */
|
||||||
|
double z_[BlackoilPhases::MaxNumPhases];
|
||||||
|
mutable double A_[BlackoilPhases::MaxNumPhases * BlackoilPhases::MaxNumPhases];
|
||||||
|
|
||||||
|
double satRv(const double press) const
|
||||||
|
{
|
||||||
|
props_.matrix(1, &press, z_, &cell_, A_, 0);
|
||||||
|
// Rv/Bg is in the oil row and gas column of A_.
|
||||||
|
// 1/Bg is in the gas row and column.
|
||||||
|
// Recall also that it is stored in column-major order.
|
||||||
|
const int opos = props_.phaseUsage().phase_pos[BlackoilPhases::Liquid];
|
||||||
|
const int gpos = props_.phaseUsage().phase_pos[BlackoilPhases::Vapour];
|
||||||
|
const int np = props_.numPhases();
|
||||||
|
return A_[np*gpos + opos] / A_[np*gpos + gpos];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -298,9 +407,14 @@ namespace Opm
|
|||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
operator()(const double /* depth */,
|
operator()(const double /* depth */,
|
||||||
const double press) const
|
const double press,
|
||||||
{
|
const double sat_gas = 0.0) const
|
||||||
return std::min(satRs(press), rs_sat_contact_);
|
{
|
||||||
|
if (sat_gas > 0.0) {
|
||||||
|
return satRs(press);
|
||||||
|
} else {
|
||||||
|
return std::min(satRs(press), rs_sat_contact_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -323,6 +437,84 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that implements "vaporized oil-gas ratio" (Rv)
|
||||||
|
* as function of depth and pressure as follows:
|
||||||
|
*
|
||||||
|
* 1. The Rv at the gas-oil contact is equal to the
|
||||||
|
* saturated Rv value, Rv_sat_contact.
|
||||||
|
*
|
||||||
|
* 2. The Rv elsewhere is equal to Rv_sat_contact, but
|
||||||
|
* constrained to the saturated value as given by the
|
||||||
|
* local pressure.
|
||||||
|
*
|
||||||
|
* This should yield Rv-values that are constant below the
|
||||||
|
* contact, and decreasing above the contact.
|
||||||
|
*/
|
||||||
|
class RvSatAtContact : public RsFunction {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* \param[in] props property object
|
||||||
|
* \param[in] cell any cell in the pvt region
|
||||||
|
* \param[in] p_contact oil pressure at the contact
|
||||||
|
*/
|
||||||
|
RvSatAtContact(const BlackoilPropertiesInterface& props, const int cell, const double p_contact)
|
||||||
|
: props_(props), cell_(cell)
|
||||||
|
{
|
||||||
|
auto pu = props_.phaseUsage();
|
||||||
|
std::fill(z_, z_ + BlackoilPhases::MaxNumPhases, 0.0);
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||||
|
z_[pu.phase_pos[BlackoilPhases::Liquid]] = 1e100;
|
||||||
|
rv_sat_contact_ = satRv(p_contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function call.
|
||||||
|
*
|
||||||
|
* \param[in] depth Depth at which to calculate RV
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* \param[in] press Pressure at which to calculate RV
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* \return Dissolved oil-gas ratio (RV) at depth @c
|
||||||
|
* depth and pressure @c press.
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
operator()(const double /*depth*/,
|
||||||
|
const double press,
|
||||||
|
const double sat_oil = 0.0) const
|
||||||
|
{
|
||||||
|
if (sat_oil > 0.0) {
|
||||||
|
return satRv(press);
|
||||||
|
} else {
|
||||||
|
return std::min(satRv(press), rv_sat_contact_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BlackoilPropertiesInterface& props_;
|
||||||
|
const int cell_;
|
||||||
|
double z_[BlackoilPhases::MaxNumPhases];
|
||||||
|
double rv_sat_contact_;
|
||||||
|
mutable double A_[BlackoilPhases::MaxNumPhases * BlackoilPhases::MaxNumPhases];
|
||||||
|
|
||||||
|
double satRv(const double press) const
|
||||||
|
{
|
||||||
|
props_.matrix(1, &press, z_, &cell_, A_, 0);
|
||||||
|
// Rv/Bg is in the oil row and gas column of A_.
|
||||||
|
// 1/Bg is in the gas row and column.
|
||||||
|
// Recall also that it is stored in column-major order.
|
||||||
|
const int opos = props_.phaseUsage().phase_pos[BlackoilPhases::Liquid];
|
||||||
|
const int gpos = props_.phaseUsage().phase_pos[BlackoilPhases::Vapour];
|
||||||
|
const int np = props_.numPhases();
|
||||||
|
return A_[np*gpos + opos] / A_[np*gpos + gpos];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Miscibility
|
} // namespace Miscibility
|
||||||
|
|
||||||
|
|
||||||
@ -355,6 +547,9 @@ namespace Opm
|
|||||||
double depth;
|
double depth;
|
||||||
double press;
|
double press;
|
||||||
} main, woc, goc;
|
} main, woc, goc;
|
||||||
|
int live_oil_table_index;
|
||||||
|
int wet_gas_table_index;
|
||||||
|
int N;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,8 +175,8 @@ namespace Opm
|
|||||||
std::vector<double> computeRs(const UnstructuredGrid& grid,
|
std::vector<double> computeRs(const UnstructuredGrid& grid,
|
||||||
const CellRangeType& cells,
|
const CellRangeType& cells,
|
||||||
const std::vector<double> oil_pressure,
|
const std::vector<double> oil_pressure,
|
||||||
const Miscibility::RsFunction& rs_func);
|
const Miscibility::RsFunction& rs_func,
|
||||||
|
const std::vector<double> gas_saturation);
|
||||||
|
|
||||||
namespace DeckDependent {
|
namespace DeckDependent {
|
||||||
|
|
||||||
@ -205,8 +205,17 @@ namespace Opm
|
|||||||
,
|
,
|
||||||
{ rec.gas_oil_contact_depth_ ,
|
{ rec.gas_oil_contact_depth_ ,
|
||||||
rec.gas_oil_cap_pressure_ }
|
rec.gas_oil_cap_pressure_ }
|
||||||
|
,
|
||||||
|
rec.live_oil_table_index_
|
||||||
|
,
|
||||||
|
rec.wet_gas_table_index_
|
||||||
|
,
|
||||||
|
rec.N_
|
||||||
};
|
};
|
||||||
|
if (record.N != 0) {
|
||||||
|
OPM_THROW(std::domain_error,
|
||||||
|
"kw EQUIL, item 9: Only N=0 supported.");
|
||||||
|
}
|
||||||
ret.push_back(record);
|
ret.push_back(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,14 +276,25 @@ namespace Opm
|
|||||||
|
|
||||||
// Create Rs functions.
|
// Create Rs functions.
|
||||||
rs_func_.reserve(rec.size());
|
rs_func_.reserve(rec.size());
|
||||||
if (deck.hasField("DISGAS")) {
|
if (deck.hasField("DISGAS")) {
|
||||||
if (deck.hasField("RSVD")) {
|
for (size_t i = 0; i < rec.size(); ++i) {
|
||||||
// Rs has been specified as a function of depth.
|
const int cell = *(eqlmap.cells(i + 1).begin());
|
||||||
OPM_THROW(std::runtime_error, "Cannot initialise: RSVD field not read by EclipseGridParser class.");
|
// TODO Check this ...
|
||||||
} else {
|
// The index <cell> is here picked as a representative for its equlibrium region,
|
||||||
// Default initialisation: constant Rs below contact, saturated above.
|
// but is below used to identify PVT region.
|
||||||
for (size_t i = 0; i < rec.size(); ++i) {
|
// This assumes that an eq-region has uniform pvt properties, is this always ok?
|
||||||
const int cell = *(eqlmap.cells(i + 1).begin());
|
// For Norne this is trivial, as there is only one active pvt-region (PVTNUM=1 for all cells):
|
||||||
|
if (rec[i].live_oil_table_index > 0) {
|
||||||
|
if (deck.hasField("RSVD")) {
|
||||||
|
// TODO When this kw is actually parsed, also check for proper number of available tables
|
||||||
|
// For now, just use dummy ...
|
||||||
|
std::vector<double> depth; depth.push_back(0.0); depth.push_back(100.0);
|
||||||
|
std::vector<double> rs; rs.push_back(0.0); rs.push_back(100.0);
|
||||||
|
rs_func_.push_back(std::make_shared<Miscibility::RsVD>(props, cell, depth, rs));
|
||||||
|
} else {
|
||||||
|
OPM_THROW(std::runtime_error, "Cannot initialise: RSVD table " << (rec[i].live_oil_table_index) << " not available.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (rec[i].goc.depth != rec[i].main.depth) {
|
if (rec[i].goc.depth != rec[i].main.depth) {
|
||||||
OPM_THROW(std::runtime_error,
|
OPM_THROW(std::runtime_error,
|
||||||
"Cannot initialise: when no explicit RSVD table is given, \n"
|
"Cannot initialise: when no explicit RSVD table is given, \n"
|
||||||
@ -289,8 +309,40 @@ namespace Opm
|
|||||||
for (size_t i = 0; i < rec.size(); ++i) {
|
for (size_t i = 0; i < rec.size(); ++i) {
|
||||||
rs_func_.push_back(std::make_shared<Miscibility::NoMixing>());
|
rs_func_.push_back(std::make_shared<Miscibility::NoMixing>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rv_func_.reserve(rec.size());
|
||||||
|
if (deck.hasField("VAPOIL")) {
|
||||||
|
for (size_t i = 0; i < rec.size(); ++i) {
|
||||||
|
const int cell = *(eqlmap.cells(i + 1).begin());
|
||||||
|
// TODO Similar as above: eq-region vs pvt-region ...
|
||||||
|
if (rec[i].wet_gas_table_index > 0) {
|
||||||
|
if (deck.hasField("RVVD")) {
|
||||||
|
// TODO When this kw is actually parsed, also check for proper number of available tables
|
||||||
|
// For now, just use dummy ...
|
||||||
|
std::vector<double> depth; depth.push_back(0.0); depth.push_back(100.0);
|
||||||
|
std::vector<double> rv; rv.push_back(0.0); rv.push_back(0.0001);
|
||||||
|
rv_func_.push_back(std::make_shared<Miscibility::RvVD>(props, cell, depth, rv));
|
||||||
|
} else {
|
||||||
|
OPM_THROW(std::runtime_error, "Cannot initialise: RVVD table " << (rec[i].wet_gas_table_index) << " not available.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rec[i].goc.depth != rec[i].main.depth) {
|
||||||
|
OPM_THROW(std::runtime_error,
|
||||||
|
"Cannot initialise: when no explicit RVVD table is given, \n"
|
||||||
|
"datum depth must be at the gas-oil-contact. "
|
||||||
|
"In EQUIL region " << (i + 1) << " (counting from 1), this does not hold.");
|
||||||
|
}
|
||||||
|
const double p_contact = rec[i].main.press + rec[i].goc.press;
|
||||||
|
rv_func_.push_back(std::make_shared<Miscibility::RvSatAtContact>(props, cell, p_contact));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < rec.size(); ++i) {
|
||||||
|
rv_func_.push_back(std::make_shared<Miscibility::NoMixing>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute pressures, saturations, rs and rv factors.
|
// Compute pressures, saturations, rs and rv factors.
|
||||||
calcPressSatRsRv(eqlmap, rec, props, G, grav);
|
calcPressSatRsRv(eqlmap, rec, props, G, grav);
|
||||||
|
|
||||||
@ -311,6 +363,7 @@ namespace Opm
|
|||||||
typedef EquilReg<RhoCalc> EqReg;
|
typedef EquilReg<RhoCalc> EqReg;
|
||||||
|
|
||||||
std::vector< std::shared_ptr<Miscibility::RsFunction> > rs_func_;
|
std::vector< std::shared_ptr<Miscibility::RsFunction> > rs_func_;
|
||||||
|
std::vector< std::shared_ptr<Miscibility::RsFunction> > rv_func_;
|
||||||
|
|
||||||
PVec pp_;
|
PVec pp_;
|
||||||
PVec sat_;
|
PVec sat_;
|
||||||
@ -335,13 +388,14 @@ namespace Opm
|
|||||||
|
|
||||||
const int repcell = *cells.begin();
|
const int repcell = *cells.begin();
|
||||||
const RhoCalc calc(props, repcell);
|
const RhoCalc calc(props, repcell);
|
||||||
|
|
||||||
const EqReg eqreg(rec[r], calc,
|
const EqReg eqreg(rec[r], calc,
|
||||||
rs_func_[r], std::make_shared<NoMix>(),
|
rs_func_[r], rv_func_[r],
|
||||||
props.phaseUsage());
|
props.phaseUsage());
|
||||||
|
|
||||||
const PVec press = phasePressures(G, eqreg, cells, grav);
|
PVec press = phasePressures(G, eqreg, cells, grav);
|
||||||
|
|
||||||
const PVec sat = phaseSaturations(eqreg, cells, props, press);
|
const PVec sat = phaseSaturations(eqreg, cells, props, press);
|
||||||
|
|
||||||
const int np = props.numPhases();
|
const int np = props.numPhases();
|
||||||
for (int p = 0; p < np; ++p) {
|
for (int p = 0; p < np; ++p) {
|
||||||
copyFromRegion(press[p], cells, pp_[p]);
|
copyFromRegion(press[p], cells, pp_[p]);
|
||||||
@ -350,8 +404,9 @@ namespace Opm
|
|||||||
if (props.phaseUsage().phase_used[BlackoilPhases::Liquid]
|
if (props.phaseUsage().phase_used[BlackoilPhases::Liquid]
|
||||||
&& props.phaseUsage().phase_used[BlackoilPhases::Vapour]) {
|
&& props.phaseUsage().phase_used[BlackoilPhases::Vapour]) {
|
||||||
const int oilpos = props.phaseUsage().phase_pos[BlackoilPhases::Liquid];
|
const int oilpos = props.phaseUsage().phase_pos[BlackoilPhases::Liquid];
|
||||||
const Vec rs = computeRs(G, cells, press[oilpos], *(rs_func_[r]));
|
const int gaspos = props.phaseUsage().phase_pos[BlackoilPhases::Vapour];
|
||||||
const Vec rv(cells.size(), 0.0);
|
const Vec rs = computeRs(G, cells, press[oilpos], *(rs_func_[r]), sat[gaspos]);
|
||||||
|
const Vec rv = computeRs(G, cells, press[gaspos], *(rv_func_[r]), sat[oilpos]);
|
||||||
copyFromRegion(rs, cells, rs_);
|
copyFromRegion(rs, cells, rs_);
|
||||||
copyFromRegion(rv, cells, rv_);
|
copyFromRegion(rv, cells, rv_);
|
||||||
}
|
}
|
||||||
|
@ -580,7 +580,7 @@ namespace Opm
|
|||||||
phaseSaturations(const Region& reg,
|
phaseSaturations(const Region& reg,
|
||||||
const CellRange& cells,
|
const CellRange& cells,
|
||||||
const BlackoilPropertiesInterface& props,
|
const BlackoilPropertiesInterface& props,
|
||||||
const std::vector< std::vector<double> >& phase_pressures)
|
std::vector< std::vector<double> >& phase_pressures)
|
||||||
{
|
{
|
||||||
const double z0 = reg.datum();
|
const double z0 = reg.datum();
|
||||||
const double zwoc = reg.zwoc ();
|
const double zwoc = reg.zwoc ();
|
||||||
@ -621,6 +621,7 @@ namespace Opm
|
|||||||
sg = satFromPc(props, gaspos, cell, pcog, increasing);
|
sg = satFromPc(props, gaspos, cell, pcog, increasing);
|
||||||
phase_saturations[gaspos][local_index] = sg;
|
phase_saturations[gaspos][local_index] = sg;
|
||||||
}
|
}
|
||||||
|
bool overlap = false;
|
||||||
if (gas && water && (sg + sw > 1.0)) {
|
if (gas && water && (sg + sw > 1.0)) {
|
||||||
// Overlapping gas-oil and oil-water transition
|
// Overlapping gas-oil and oil-water transition
|
||||||
// zones can lead to unphysical saturations when
|
// zones can lead to unphysical saturations when
|
||||||
@ -631,8 +632,32 @@ namespace Opm
|
|||||||
sg = 1.0 - sw;
|
sg = 1.0 - sw;
|
||||||
phase_saturations[waterpos][local_index] = sw;
|
phase_saturations[waterpos][local_index] = sw;
|
||||||
phase_saturations[gaspos][local_index] = sg;
|
phase_saturations[gaspos][local_index] = sg;
|
||||||
|
overlap = true;
|
||||||
}
|
}
|
||||||
phase_saturations[oilpos][local_index] = 1.0 - sw - sg;
|
phase_saturations[oilpos][local_index] = 1.0 - sw - sg;
|
||||||
|
|
||||||
|
// Adjust phase pressures for max and min saturation ...
|
||||||
|
double pc[BlackoilPhases::MaxNumPhases];
|
||||||
|
double sat[BlackoilPhases::MaxNumPhases];
|
||||||
|
if (sw > smax[waterpos]-1.0e-6) {
|
||||||
|
sat[waterpos] = smax[waterpos];
|
||||||
|
props.capPress(1, sat, &cell, pc, 0);
|
||||||
|
phase_pressures[oilpos][local_index] = phase_pressures[waterpos][local_index] + pc[waterpos];
|
||||||
|
} else if (overlap || sg > smax[gaspos]-1.0e-6) {
|
||||||
|
sat[gaspos] = smax[gaspos];
|
||||||
|
props.capPress(1, sat, &cell, pc, 0);
|
||||||
|
phase_pressures[oilpos][local_index] = phase_pressures[gaspos][local_index] - pc[gaspos];
|
||||||
|
}
|
||||||
|
if (sg < smin[gaspos]+1.0e-6) {
|
||||||
|
sat[gaspos] = smin[gaspos];
|
||||||
|
props.capPress(1, sat, &cell, pc, 0);
|
||||||
|
phase_pressures[gaspos][local_index] = phase_pressures[oilpos][local_index] + pc[gaspos];
|
||||||
|
}
|
||||||
|
if (sw < smin[waterpos]+1.0e-6) {
|
||||||
|
sat[waterpos] = smin[waterpos];
|
||||||
|
props.capPress(1, sat, &cell, pc, 0);
|
||||||
|
phase_pressures[waterpos][local_index] = phase_pressures[oilpos][local_index] - pc[waterpos];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return phase_saturations;
|
return phase_saturations;
|
||||||
}
|
}
|
||||||
@ -659,20 +684,19 @@ namespace Opm
|
|||||||
std::vector<double> computeRs(const UnstructuredGrid& grid,
|
std::vector<double> computeRs(const UnstructuredGrid& grid,
|
||||||
const CellRangeType& cells,
|
const CellRangeType& cells,
|
||||||
const std::vector<double> oil_pressure,
|
const std::vector<double> oil_pressure,
|
||||||
const Miscibility::RsFunction& rs_func)
|
const Miscibility::RsFunction& rs_func,
|
||||||
|
const std::vector<double> gas_saturation)
|
||||||
{
|
{
|
||||||
assert(grid.dimensions == 3);
|
assert(grid.dimensions == 3);
|
||||||
std::vector<double> rs(cells.size());
|
std::vector<double> rs(cells.size());
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (auto it = cells.begin(); it != cells.end(); ++it, ++count) {
|
for (auto it = cells.begin(); it != cells.end(); ++it, ++count) {
|
||||||
const double depth = grid.cell_centroids[3*(*it) + 2];
|
const double depth = grid.cell_centroids[3*(*it) + 2];
|
||||||
rs[count] = rs_func(depth, oil_pressure[count]);
|
rs[count] = rs_func(depth, oil_pressure[count], gas_saturation[count]);
|
||||||
}
|
}
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Equil
|
} // namespace Equil
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user