implement two-phase blackoil simulations

This commit is contained in:
Andreas Lauser
2016-11-15 18:00:48 +01:00
parent 6cf1eab4f4
commit c4c00bdaaa
5 changed files with 191 additions and 67 deletions

View File

@@ -126,9 +126,10 @@ public:
assert( gridManager.grid().size(/*codim=*/0) == static_cast<int>(numEquilElems) );
// initialize the boiler plate of opm-core the state structure.
const auto opmPhaseUsage = opmBlackoilProps.phaseUsage();
Opm::BlackoilState opmBlackoilState(numEquilElems,
/*numFaces=*/0, // we don't care here
numPhases);
opmPhaseUsage.num_phases);
// do the actual computation.
Opm::initStateEquil(equilGrid,
@@ -149,7 +150,27 @@ public:
// set the phase saturations
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar S = opmBlackoilState.saturation()[equilElemIdx*numPhases + phaseIdx];
Scalar S;
if (!FluidSystem::phaseIsActive(phaseIdx))
S = 0.0;
else {
unsigned opmPhasePos = 10000;
switch (phaseIdx) {
case oilPhaseIdx:
opmPhasePos = opmPhaseUsage.phase_pos[Opm::BlackoilPhases::Liquid];
break;
case gasPhaseIdx:
opmPhasePos = opmPhaseUsage.phase_pos[Opm::BlackoilPhases::Vapour];
break;
case waterPhaseIdx:
opmPhasePos = opmPhaseUsage.phase_pos[Opm::BlackoilPhases::Aqua];
break;
}
S = opmBlackoilState.saturation()[equilElemIdx*opmPhaseUsage.num_phases
+ opmPhasePos];
}
fluidState.setSaturation(phaseIdx, S);
}
@@ -179,7 +200,7 @@ public:
// water component.
fluidState.setMoleFraction(waterPhaseIdx, waterCompIdx, 1.0);
if (gridManager.deck()->hasKeyword("DISGAS")) {
if (FluidSystem::enableDissolvedGas()) {
// for gas and oil we have to translate surface volumes to mole fractions
// before we can set the composition in the fluid state
Scalar Rs = opmBlackoilState.gasoilratio()[equilElemIdx];
@@ -197,7 +218,7 @@ public:
}
// retrieve the surface volume of vaporized gas
if (gridManager.deck()->hasKeyword("VAPOIL")) {
if (FluidSystem::enableVaporizedOil()) {
Scalar Rv = opmBlackoilState.rv()[equilElemIdx];
Scalar RvSat = FluidSystem::saturatedDissolutionFactor(fluidState, gasPhaseIdx, regionIdx);

View File

@@ -102,6 +102,7 @@ protected:
template <class TypeTag>
class EclTransExtensiveQuantities
{
typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
@@ -248,6 +249,9 @@ protected:
Scalar distZ = zIn - zEx;
for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
// check shortcut: if the mobility of the phase is zero in the interior as
// well as the exterior DOF, we can skip looking at the phase.
if (intQuantsIn.mobility(phaseIdx) < 1e-18 && intQuantsEx.mobility(phaseIdx) < 1e-18) {

View File

@@ -49,6 +49,7 @@ NEW_TYPE_TAG(EclOutputBlackOil);
NEW_PROP_TAG(EclOutputWriteSaturations);
NEW_PROP_TAG(EclOutputWritePressures);
NEW_PROP_TAG(EclOutputWriteGasDissolutionFactor);
NEW_PROP_TAG(EclOutputWriteOilVaporizationFactor);
NEW_PROP_TAG(EclOutputWriteGasFormationVolumeFactor);
NEW_PROP_TAG(EclOutputWriteOilFormationVolumeFactor);
NEW_PROP_TAG(EclOutputWriteOilSaturationPressure);
@@ -57,6 +58,7 @@ NEW_PROP_TAG(EclOutputWriteOilSaturationPressure);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteSaturations, true);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWritePressures, true);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteGasDissolutionFactor, true);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteOilVaporizationFactor, false);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteGasFormationVolumeFactor, true);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteOilFormationVolumeFactor, true);
SET_BOOL_PROP(EclOutputBlackOil, EclOutputWriteOilSaturationPressure, false);
@@ -114,7 +116,10 @@ public:
"Include the absolute pressures of all fluid phases in the "
"ECL output files");
EWOMS_REGISTER_PARAM(TypeTag, bool, EclOutputWriteGasDissolutionFactor,
"Include the gas dissolution factor in the "
"Include the gas dissolution factor of saturated oil in the "
"ECL output files");
EWOMS_REGISTER_PARAM(TypeTag, bool, EclOutputWriteOilVaporizationFactor,
"Include the oil vaporization factor of saturated gas in the "
"ECL output files");
EWOMS_REGISTER_PARAM(TypeTag, bool, EclOutputWriteGasFormationVolumeFactor,
"Include the gas formation volume factor in the "
@@ -147,6 +152,8 @@ public:
}
if (gasDissolutionFactorOutput_())
this->resizeScalarBuffer_(gasDissolutionFactor_, bufferType);
if (oilVaporizationFactorOutput_())
this->resizeScalarBuffer_(oilVaporizationFactor_, bufferType);
if (gasFormationVolumeFactorOutput_())
this->resizeScalarBuffer_(gasFormationVolumeFactor_, bufferType);
if (saturatedOilFormationVolumeFactorOutput_())
@@ -177,12 +184,18 @@ public:
if (saturationsOutput_()) {
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
saturation_[phaseIdx][globalDofIdx] = Toolbox::value(fs.saturation(phaseIdx));
Valgrind::CheckDefined(saturation_[phaseIdx][globalDofIdx]);
}
}
if (pressuresOutput_()) {
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
pressure_[phaseIdx][globalDofIdx] = Toolbox::value(fs.pressure(phaseIdx));
Valgrind::CheckDefined(pressure_[phaseIdx][globalDofIdx]);
}
@@ -193,6 +206,12 @@ public:
FluidSystem::template saturatedDissolutionFactor<FluidState, Scalar>(fs, gasPhaseIdx, pvtRegionIdx, SoMax);
Valgrind::CheckDefined(gasDissolutionFactor_[globalDofIdx]);
}
if (oilVaporizationFactorOutput_()) {
Scalar SoMax = elemCtx.model().maxOilSaturation(globalDofIdx);
gasDissolutionFactor_[globalDofIdx] =
FluidSystem::template saturatedDissolutionFactor<FluidState, Scalar>(fs, oilPhaseIdx, pvtRegionIdx, SoMax);
Valgrind::CheckDefined(gasDissolutionFactor_[globalDofIdx]);
}
if (gasFormationVolumeFactorOutput_()) {
gasFormationVolumeFactor_[globalDofIdx] =
1.0/FluidSystem::template inverseFormationVolumeFactor<FluidState, Scalar>(fs, gasPhaseIdx, pvtRegionIdx);
@@ -247,6 +266,10 @@ public:
deckUnits.siToDeck(gasDissolutionFactor_, DeckUnits::gasDissolutionFactor);
this->commitScalarBuffer_(writer, "RS", gasDissolutionFactor_, bufferType);
}
if (oilVaporizationFactorOutput_()) {
deckUnits.siToDeck(oilVaporizationFactor_, DeckUnits::oilVaporizationFactor);
this->commitScalarBuffer_(writer, "RV", oilVaporizationFactor_, bufferType);
}
if (gasFormationVolumeFactorOutput_()) {
// no unit conversion required
this->commitScalarBuffer_(writer, "BG", gasFormationVolumeFactor_, bufferType);
@@ -269,20 +292,49 @@ private:
{ return EWOMS_GET_PARAM(TypeTag, bool, EclOutputWritePressures); }
static bool gasDissolutionFactorOutput_()
{ return EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteGasDissolutionFactor); }
{
return
FluidSystem::phaseIsActive(oilPhaseIdx) &&
FluidSystem::phaseIsActive(gasPhaseIdx) &&
EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteGasDissolutionFactor);
}
static bool gasFormationVolumeFactorOutput_()
{ return EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteGasFormationVolumeFactor); }
{
return
FluidSystem::phaseIsActive(oilPhaseIdx) &&
FluidSystem::phaseIsActive(gasPhaseIdx) &&
EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteGasFormationVolumeFactor);
}
static bool oilVaporizationFactorOutput_()
{
return
FluidSystem::phaseIsActive(oilPhaseIdx) &&
FluidSystem::phaseIsActive(gasPhaseIdx) &&
EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteOilVaporizationFactor);
}
static bool saturatedOilFormationVolumeFactorOutput_()
{ return EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteOilFormationVolumeFactor); }
{
return
FluidSystem::phaseIsActive(oilPhaseIdx) &&
FluidSystem::phaseIsActive(gasPhaseIdx) &&
EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteOilFormationVolumeFactor);
}
static bool oilSaturationPressureOutput_()
{ return EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteOilSaturationPressure); }
{
return
FluidSystem::phaseIsActive(oilPhaseIdx) &&
FluidSystem::phaseIsActive(gasPhaseIdx) &&
EWOMS_GET_PARAM(TypeTag, bool, EclOutputWriteOilSaturationPressure);
}
ScalarBuffer saturation_[numPhases];
ScalarBuffer pressure_[numPhases];
ScalarBuffer gasDissolutionFactor_;
ScalarBuffer oilVaporizationFactor_;
ScalarBuffer gasFormationVolumeFactor_;
ScalarBuffer saturatedOilFormationVolumeFactor_;
ScalarBuffer oilSaturationPressure_;

View File

@@ -145,6 +145,9 @@ class EclPeacemanWell : public BaseAuxiliaryModule<TypeTag>
{
const auto& fs = intQuants.fluidState();
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
pressure[phaseIdx] = fs.pressure(phaseIdx);
density[phaseIdx] = fs.density(phaseIdx);
mobility[phaseIdx] = intQuants.mobility(phaseIdx);
@@ -418,6 +421,9 @@ public:
*std::max<Scalar>(1e5, actualBottomHolePressure_);
computeVolumetricDofRates_(resvRates, actualBottomHolePressure_ + eps, *dofVariables_[gridDofIdx]);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
modelRate.setVolumetricRate(fluidState, phaseIdx, resvRates[phaseIdx]);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
q[compIdx] += modelRate[compIdx];
@@ -426,6 +432,9 @@ public:
// then, we subtract the source rates for a undisturbed well.
computeVolumetricDofRates_(resvRates, actualBottomHolePressure_, *dofVariables_[gridDofIdx]);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
modelRate.setVolumetricRate(fluidState, phaseIdx, resvRates[phaseIdx]);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
q[compIdx] -= modelRate[compIdx];
@@ -1114,6 +1123,9 @@ public:
RateVector modelRate;
const auto& intQuants = context.intensiveQuantities(dofIdx, timeIdx);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
modelRate.setVolumetricRate(intQuants.fluidState(), phaseIdx, volumetricRates[phaseIdx]);
for (unsigned eqIdx = 0; eqIdx < q.size(); ++eqIdx)
q[eqIdx] += modelRate[eqIdx];
@@ -1176,6 +1188,9 @@ protected:
Scalar g = simulator_.problem().gravity()[dimWorld - 1];
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
// well model due to Peaceman; see Chen et al., p. 449
// phase pressure in grid cell
@@ -1198,8 +1213,12 @@ protected:
// there should only be injected phase present, so its mobility should be
// 1/viscosity...
lambda = 0.0;
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
lambda += DofVarsToolbox::template decay<DofEval>(dofVars.mobility[phaseIdx]);
for (unsigned phase2Idx = 0; phase2Idx < numPhases; ++phase2Idx) {
if (!FluidSystem::phaseIsActive(phase2Idx))
continue;
lambda += DofVarsToolbox::template decay<DofEval>(dofVars.mobility[phase2Idx]);
}
}
else
OPM_THROW(std::logic_error,
@@ -1236,8 +1255,12 @@ protected:
Eval computeWeightedRate_(const std::array<Eval, numPhases>& volRates) const
{
Eval result = 0;
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
result += volRates[phaseIdx]*volumetricWeight_[phaseIdx];
}
return result;
}
@@ -1265,38 +1288,41 @@ protected:
Scalar rhoWaterSurface = FluidSystem::referenceDensity(waterPhaseIdx, regionIdx);
// oil
surfaceRates[oilPhaseIdx] =
// oil in gas phase
reservoirRate[gasPhaseIdx]
* Toolbox::value(dofVars.density[gasPhaseIdx])
* Toolbox::value(dofVars.gasMassFraction[oilCompIdx])
/ rhoOilSurface
+
// oil in oil phase
reservoirRate[oilPhaseIdx]
* Toolbox::value(dofVars.density[oilPhaseIdx])
* Toolbox::value(dofVars.oilMassFraction[oilCompIdx])
/ rhoOilSurface;
if (FluidSystem::phaseIsActive(oilPhaseIdx))
surfaceRates[oilPhaseIdx] =
// oil in gas phase
reservoirRate[gasPhaseIdx]
* Toolbox::value(dofVars.density[gasPhaseIdx])
* Toolbox::value(dofVars.gasMassFraction[oilCompIdx])
/ rhoOilSurface
+
// oil in oil phase
reservoirRate[oilPhaseIdx]
* Toolbox::value(dofVars.density[oilPhaseIdx])
* Toolbox::value(dofVars.oilMassFraction[oilCompIdx])
/ rhoOilSurface;
// gas
surfaceRates[gasPhaseIdx] =
// gas in gas phase
reservoirRate[gasPhaseIdx]
* Toolbox::value(dofVars.density[gasPhaseIdx])
* Toolbox::value(dofVars.gasMassFraction[gasCompIdx])
/ rhoGasSurface
+
// gas in oil phase
reservoirRate[oilPhaseIdx]
* Toolbox::value(dofVars.density[oilPhaseIdx])
* Toolbox::value(dofVars.oilMassFraction[gasCompIdx])
/ rhoGasSurface;
if (FluidSystem::phaseIsActive(gasPhaseIdx))
surfaceRates[gasPhaseIdx] =
// gas in gas phase
reservoirRate[gasPhaseIdx]
* Toolbox::value(dofVars.density[gasPhaseIdx])
* Toolbox::value(dofVars.gasMassFraction[gasCompIdx])
/ rhoGasSurface
+
// gas in oil phase
reservoirRate[oilPhaseIdx]
* Toolbox::value(dofVars.density[oilPhaseIdx])
* Toolbox::value(dofVars.oilMassFraction[gasCompIdx])
/ rhoGasSurface;
// water
surfaceRates[waterPhaseIdx] =
reservoirRate[waterPhaseIdx]
* Toolbox::value(dofVars.density[waterPhaseIdx])
/ rhoWaterSurface;
if (FluidSystem::phaseIsActive(waterPhaseIdx))
surfaceRates[waterPhaseIdx] =
reservoirRate[waterPhaseIdx]
* Toolbox::value(dofVars.density[waterPhaseIdx])
/ rhoWaterSurface;
}
/*!
@@ -1333,6 +1359,9 @@ protected:
computeSurfaceRates_(volumetricSurfaceRates, volumetricReservoirRates, *tmp);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
overallResvRates[phaseIdx] += volumetricReservoirRates[phaseIdx];
overallSurfaceRates[phaseIdx] += volumetricSurfaceRates[phaseIdx];
}
@@ -1459,8 +1488,12 @@ protected:
std::array<BhpEval, numPhases> surfaceRates;
computeSurfaceRates_(surfaceRates, resvRates, *dofVars);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
totalSurfaceRates[phaseIdx] += surfaceRates[phaseIdx];
}
resvRate += computeWeightedRate_(resvRates);
}
@@ -1486,8 +1519,12 @@ protected:
// fluids are produced on the surface...
maxSurfaceRate = 0.0;
surfaceRate = 0.0;
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
if (!FluidSystem::phaseIsActive(phaseIdx))
continue;
surfaceRate += totalSurfaceRates[phaseIdx];
}
// don't care about the reservoir rate...
maxResvRate = 1e30;

View File

@@ -1069,25 +1069,26 @@ private:
// initial condition that conserves the total mass specified by these values.
useMassConservativeInitialCondition_ = true;
bool enableDisgas = deck->hasKeyword("DISGAS");
bool enableVapoil = deck->hasKeyword("VAPOIL");
// make sure all required quantities are enables
if (!deck->hasKeyword("SWAT") ||
!deck->hasKeyword("SGAS"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the presence of the SWAT "
"and SGAS keywords if the model is initialized explicitly");
if (!deck->hasKeyword("PRESSURE"))
if (FluidSystem::phaseIsActive(waterPhaseIdx) && !deck->hasKeyword("SWAT"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the presence of the SWAT keyword if "
"the water phase is active");
if (FluidSystem::phaseIsActive(gasPhaseIdx) && !deck->hasKeyword("SGAS"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the presence of the SGAS keyword if "
"the gas phase is active");
if (!deck->hasKeyword("PRESSURE"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the presence of the PRESSURE "
"keyword if the model is initialized explicitly");
if (enableDisgas && !deck->hasKeyword("RS"))
OPM_THROW(std::runtime_error,
if (FluidSystem::enableDissolvedGas() && !deck->hasKeyword("RS"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the RS keyword to be present if"
" dissolved gas is enabled");
if (enableVapoil && !deck->hasKeyword("RV"))
OPM_THROW(std::runtime_error,
if (FluidSystem::enableVaporizedOil() && !deck->hasKeyword("RV"))
OPM_THROW(std::runtime_error,
"The ECL input file requires the RV keyword to be present if"
" vaporized oil is enabled");
@@ -1095,17 +1096,28 @@ private:
initialFluidStates_.resize(numDof);
const std::vector<double>& waterSaturationData =
deck->getKeyword("SWAT").getSIDoubleData();
const std::vector<double>& gasSaturationData =
deck->getKeyword("SGAS").getSIDoubleData();
const auto& cartSize = this->simulator().gridManager().cartesianDimensions();
size_t numCartesianCells = cartSize[0] * cartSize[1] * cartSize[2];
std::vector<double> waterSaturationData;
if (FluidSystem::phaseIsActive(waterPhaseIdx))
waterSaturationData = deck->getKeyword("SWAT").getSIDoubleData();
else
waterSaturationData.resize(numCartesianCells, 0.0);
std::vector<double> gasSaturationData;
if (FluidSystem::phaseIsActive(gasPhaseIdx))
gasSaturationData = deck->getKeyword("SGAS").getSIDoubleData();
else
gasSaturationData.resize(numCartesianCells, 0.0);
const std::vector<double>& pressureData =
deck->getKeyword("PRESSURE").getSIDoubleData();
const std::vector<double> *rsData = 0;
if (enableDisgas)
if (FluidSystem::enableDissolvedGas())
rsData = &deck->getKeyword("RS").getSIDoubleData();
const std::vector<double> *rvData = 0;
if (enableVapoil)
if (FluidSystem::enableVaporizedOil())
rvData = &deck->getKeyword("RV").getSIDoubleData();
// initial reservoir temperature
const std::vector<double>& tempiData =
@@ -1113,14 +1125,12 @@ private:
// make sure that the size of the data arrays is correct
#ifndef NDEBUG
const auto& cartSize = this->simulator().gridManager().cartesianDimensions();
size_t numCartesianCells = cartSize[0] * cartSize[1] * cartSize[2];
assert(waterSaturationData.size() == numCartesianCells);
assert(gasSaturationData.size() == numCartesianCells);
assert(pressureData.size() == numCartesianCells);
if (enableDisgas)
if (FluidSystem::enableDissolvedGas())
assert(rsData->size() == numCartesianCells);
if (enableVapoil)
if (FluidSystem::enableVaporizedOil())
assert(rvData->size() == numCartesianCells);
#endif
@@ -1182,7 +1192,7 @@ private:
dofFluidState.setMoleFraction(gasPhaseIdx, gasCompIdx, 1.0);
dofFluidState.setMoleFraction(oilPhaseIdx, oilCompIdx, 1.0);
if (enableDisgas) {
if (FluidSystem::enableDissolvedGas()) {
Scalar RsSat = FluidSystem::saturatedDissolutionFactor(dofFluidState, oilPhaseIdx, pvtRegionIdx);
Scalar RsReal = (*rsData)[cartesianDofIdx];
@@ -1207,7 +1217,7 @@ private:
dofFluidState.setMoleFraction(oilPhaseIdx, oilCompIdx, 1.0 - xoGReal);
}
if (enableVapoil) {
if (FluidSystem::enableVaporizedOil()) {
Scalar RvSat = FluidSystem::saturatedDissolutionFactor(dofFluidState, gasPhaseIdx, pvtRegionIdx);
Scalar RvReal = (*rvData)[cartesianDofIdx];