Implementation of live gas

The simulator now handles live gas as well as live oil.
The primary variables are Po,Sw and Rs,Rv or Sg depending on fluid
condition
State 1 Gas only (Undersaturated gas): Po, Sw and Rv
State 2 Gas and oil: Po, Sw and Sg
State 3 Oil only (Undersaturated oil): Po, Sw and Rs

This commit includes:
1. New interfaces for the vapor oil/gas ratios (Rv)
2. Modifications in the equations to handle rvs
3. New definition of ADI variable to handle changing primary variables
4. Modifications in the solution updates to handle changing primary
variable
5. Some changes in the appleyard process to sync with Mrsts livegas
implementation.

NOTE:
The implementation is tested on the liveoil cases SPE1 and a simplified
SPE9 and produces the same results as the old code.
The simulator is not yet able to converge on SPE3 with livegas present.
For SPE3 to converge a more robust well implementation is needed. The
current simulator reproduce the results of Mrst when a similar well
model is used in Mrst as is currently implemented OPM.
This commit is contained in:
Tor Harald Sandve
2014-01-10 14:19:37 +01:00
parent 3c5b0b9e73
commit ed02b4a91f
5 changed files with 478 additions and 137 deletions

View File

@@ -28,6 +28,7 @@
#include <opm/core/props/pvt/SinglePvtDead.hpp>
#include <opm/core/props/pvt/SinglePvtDeadSpline.hpp>
#include <opm/core/props/pvt/SinglePvtLiveOil.hpp>
#include <opm/core/props/pvt/SinglePvtLiveGas.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/Units.hpp>
@@ -108,8 +109,8 @@ namespace Opm
} else {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_));
}
// } else if (deck.hasField("PVTG")) {
// props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_));
} else if (deck.hasField("PVTG")) {
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_));
} else {
OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n");
}
@@ -256,6 +257,29 @@ namespace Opm
return mu;
}
/// Gas viscosity.
/// \param[in] pg Array of n gas pressure values.
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
/// \return Array of n viscosity values.
V BlackoilPropsAdFromDeck::muGas(const V& pg,
const V& rv,
const std::vector<PhasePresence>& cond,
const Cells& cells) const
{
if (!phase_usage_.phase_used[Gas]) {
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
}
const int n = cells.size();
assert(pg.size() == n);
V mu(n);
V dmudp(n);
V dmudr(n);
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.data(), rv.data(),&cond[0],
mu.data(), dmudp.data(), dmudr.data());
return mu;
}
/// Water viscosity.
/// \param[in] pw Array of n water pressure values.
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
@@ -332,9 +356,9 @@ namespace Opm
V mu(n);
V dmudp(n);
V dmudr(n);
const double* rs = 0;
const double* rv = 0;
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.value().data(), rs,
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.value().data(), rv,
mu.data(), dmudp.data(), dmudr.data());
ADB::M dmudp_diag = spdiag(dmudp);
@@ -346,6 +370,37 @@ namespace Opm
return ADB::function(mu, jacs);
}
/// Gas viscosity.
/// \param[in] pg Array of n gas pressure values.
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
/// \return Array of n viscosity values.
ADB BlackoilPropsAdFromDeck::muGas(const ADB& pg,
const ADB& rv,
const std::vector<PhasePresence>& cond,
const Cells& cells) const
{
if (!phase_usage_.phase_used[Gas]) {
OPM_THROW(std::runtime_error, "Cannot call muGas(): gas phase not present.");
}
const int n = cells.size();
assert(pg.value().size() == n);
V mu(n);
V dmudp(n);
V dmudr(n);
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.value().data(), rv.value().data(),&cond[0],
mu.data(), dmudp.data(), dmudr.data());
ADB::M dmudp_diag = spdiag(dmudp);
ADB::M dmudr_diag = spdiag(dmudr);
const int num_blocks = pg.numBlocks();
std::vector<ADB::M> jacs(num_blocks);
for (int block = 0; block < num_blocks; ++block) {
jacs[block] = dmudp_diag * pg.derivative()[block] + dmudr_diag * rv.derivative()[block];
}
return ADB::function(mu, jacs);
}
// ------ Formation volume factor (b) ------
@@ -585,10 +640,11 @@ namespace Opm
b.data(), dbdp.data(), dbdr.data());
ADB::M dbdp_diag = spdiag(dbdp);
ADB::M dmudr_diag = spdiag(dbdr);
const int num_blocks = pg.numBlocks();
std::vector<ADB::M> jacs(num_blocks);
for (int block = 0; block < num_blocks; ++block) {
jacs[block] = dbdp_diag * pg.derivative()[block];
jacs[block] = dbdp_diag * pg.derivative()[block] + dmudr_diag * rv.derivative()[block];;
}
return ADB::function(b, jacs);
}
@@ -655,7 +711,7 @@ namespace Opm
assert(po.size() == n);
V rv(n);
V drvdp(n);
props_[Oil]->rvSat(n, po.data(), rv.data(), drvdp.data());
props_[Gas]->rvSat(n, po.data(), rv.data(), drvdp.data());
return rv;
}
@@ -673,7 +729,7 @@ namespace Opm
assert(po.size() == n);
V rv(n);
V drvdp(n);
props_[Oil]->rvSat(n, po.value().data(), rv.data(), drvdp.data());
props_[Gas]->rvSat(n, po.value().data(), rv.data(), drvdp.data());
ADB::M drvdp_diag = spdiag(drvdp);
const int num_blocks = po.numBlocks();
std::vector<ADB::M> jacs(num_blocks);