mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-02 05:49:09 -06:00
1091 lines
49 KiB
C++
1091 lines
49 KiB
C++
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
// vi: set et ts=4 sw=4 sts=4:
|
|
/*
|
|
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 2 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/>.
|
|
Consult the COPYING file in the top-level source directory of this
|
|
module for the precise wording of the license and the list of
|
|
copyright holders.
|
|
*/
|
|
/*!
|
|
* \file
|
|
*
|
|
* \copydoc Opm::BlackOilPrimaryVariables
|
|
*/
|
|
#ifndef EWOMS_BLACK_OIL_PRIMARY_VARIABLES_HH
|
|
#define EWOMS_BLACK_OIL_PRIMARY_VARIABLES_HH
|
|
|
|
#include "blackoilproperties.hh"
|
|
#include "blackoilsolventmodules.hh"
|
|
#include "blackoilextbomodules.hh"
|
|
#include "blackoilpolymermodules.hh"
|
|
#include "blackoilenergymodules.hh"
|
|
#include "blackoilfoammodules.hh"
|
|
#include "blackoilbrinemodules.hh"
|
|
#include "blackoilmicpmodules.hh"
|
|
|
|
#include <opm/models/discretization/common/fvbaseprimaryvariables.hh>
|
|
|
|
#include <dune/common/fvector.hh>
|
|
|
|
#include <opm/material/constraintsolvers/NcpFlash.hpp>
|
|
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
|
|
#include <opm/material/fluidstates/SimpleModularFluidState.hpp>
|
|
#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
|
|
#include <opm/material/common/Valgrind.hpp>
|
|
|
|
namespace Opm {
|
|
template <class TypeTag, bool enableSolvent>
|
|
class BlackOilSolventModule;
|
|
|
|
template <class TypeTag, bool enableExtbo>
|
|
class BlackOilExtboModule;
|
|
|
|
template <class TypeTag, bool enablePolymer>
|
|
class BlackOilPolymerModule;
|
|
|
|
template <class TypeTag, bool enableBrine>
|
|
class BlackOilBrineModule;
|
|
|
|
/*!
|
|
* \ingroup BlackOilModel
|
|
*
|
|
* \brief Represents the primary variables used by the black-oil model.
|
|
*/
|
|
template <class TypeTag>
|
|
class BlackOilPrimaryVariables : public FvBasePrimaryVariables<TypeTag>
|
|
{
|
|
using ParentType = FvBasePrimaryVariables<TypeTag>;
|
|
using Implementation = GetPropType<TypeTag, Properties::PrimaryVariables>;
|
|
|
|
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
|
|
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
|
|
using Indices = GetPropType<TypeTag, Properties::Indices>;
|
|
using Problem = GetPropType<TypeTag, Properties::Problem>;
|
|
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
|
|
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
|
|
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
|
|
|
|
// number of equations
|
|
enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
|
|
|
|
// primary variable indices
|
|
enum { waterSaturationIdx = Indices::waterSaturationIdx };
|
|
enum { pressureSwitchIdx = Indices::pressureSwitchIdx };
|
|
enum { compositionSwitchIdx = Indices::compositionSwitchIdx };
|
|
enum { saltConcentrationIdx = Indices::saltConcentrationIdx };
|
|
|
|
static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
|
|
static constexpr bool waterEnabled = Indices::waterEnabled;
|
|
static constexpr bool gasEnabled = Indices::gasEnabled;
|
|
static constexpr bool oilEnabled = Indices::oilEnabled;
|
|
|
|
// phase indices from the fluid system
|
|
enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
|
|
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
|
|
enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
|
|
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
|
|
|
|
// component indices from the fluid system
|
|
enum { numComponents = getPropValue<TypeTag, Properties::NumComponents>() };
|
|
enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
|
|
enum { enableExtbo = getPropValue<TypeTag, Properties::EnableExtbo>() };
|
|
enum { enablePolymer = getPropValue<TypeTag, Properties::EnablePolymer>() };
|
|
enum { enableFoam = getPropValue<TypeTag, Properties::EnableFoam>() };
|
|
enum { enableBrine = getPropValue<TypeTag, Properties::EnableBrine>() };
|
|
enum { enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>() };
|
|
enum { enableEvaporation = getPropValue<TypeTag, Properties::EnableEvaporation>() };
|
|
enum { enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>() };
|
|
enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
|
|
enum { gasCompIdx = FluidSystem::gasCompIdx };
|
|
enum { waterCompIdx = FluidSystem::waterCompIdx };
|
|
enum { oilCompIdx = FluidSystem::oilCompIdx };
|
|
|
|
using Toolbox = MathToolbox<Evaluation>;
|
|
using ComponentVector = Dune::FieldVector<Scalar, numComponents>;
|
|
using SolventModule = BlackOilSolventModule<TypeTag, enableSolvent>;
|
|
using ExtboModule = BlackOilExtboModule<TypeTag, enableExtbo>;
|
|
using PolymerModule = BlackOilPolymerModule<TypeTag, enablePolymer>;
|
|
using EnergyModule = BlackOilEnergyModule<TypeTag, enableEnergy>;
|
|
using FoamModule = BlackOilFoamModule<TypeTag, enableFoam>;
|
|
using BrineModule = BlackOilBrineModule<TypeTag, enableBrine>;
|
|
using MICPModule = BlackOilMICPModule<TypeTag, enableMICP>;
|
|
|
|
static_assert(numPhases == 3, "The black-oil model assumes three phases!");
|
|
static_assert(numComponents == 3, "The black-oil model assumes three components!");
|
|
|
|
public:
|
|
enum PrimaryVarsMeaning {
|
|
Sw_po_Sg, // threephase case
|
|
Sw_po_Rs, // water + oil case
|
|
Sw_pg_Rv, // water + gas case
|
|
Rvw_po_Sg, // gas + oil case
|
|
Rvw_pg_Rv, //gas only
|
|
OnePhase_p, // onephase case
|
|
};
|
|
|
|
enum PrimaryVarsMeaningBrine {
|
|
Cs, // salt concentration
|
|
Sp, // (precipitated) salt saturation
|
|
};
|
|
|
|
BlackOilPrimaryVariables()
|
|
: ParentType()
|
|
{
|
|
Valgrind::SetUndefined(*this);
|
|
pvtRegionIdx_ = 0;
|
|
}
|
|
|
|
/*!
|
|
* \copydoc ImmisciblePrimaryVariables::ImmisciblePrimaryVariables(Scalar)
|
|
*/
|
|
BlackOilPrimaryVariables(Scalar value)
|
|
: ParentType(value)
|
|
{
|
|
Valgrind::SetUndefined(primaryVarsMeaning_);
|
|
pvtRegionIdx_ = 0;
|
|
}
|
|
|
|
/*!
|
|
* \copydoc ImmisciblePrimaryVariables::ImmisciblePrimaryVariables(const ImmisciblePrimaryVariables& )
|
|
*/
|
|
BlackOilPrimaryVariables(const BlackOilPrimaryVariables& value) = default;
|
|
|
|
/*!
|
|
* \brief Set the index of the region which should be used for PVT properties.
|
|
*
|
|
* The concept of PVT regions is a hack to work around the fact that the
|
|
* pseudo-components used by the black oil model (i.e., oil, gas and water) change
|
|
* their composition within the spatial domain. We implement them because, the ECL
|
|
* file format mandates them.
|
|
*/
|
|
void setPvtRegionIndex(unsigned value)
|
|
{ pvtRegionIdx_ = static_cast<unsigned short>(value); }
|
|
|
|
/*!
|
|
* \brief Return the index of the region which should be used for PVT properties.
|
|
*/
|
|
unsigned pvtRegionIndex() const
|
|
{ return pvtRegionIdx_; }
|
|
|
|
/*!
|
|
* \brief Return the interpretation which should be applied to the switching primary
|
|
* variables.
|
|
*/
|
|
PrimaryVarsMeaning primaryVarsMeaning() const
|
|
{ return primaryVarsMeaning_; }
|
|
|
|
/*!
|
|
* \brief Set the interpretation which should be applied to the switching primary
|
|
* variables.
|
|
*/
|
|
void setPrimaryVarsMeaning(PrimaryVarsMeaning newMeaning)
|
|
{ primaryVarsMeaning_ = newMeaning; }
|
|
|
|
PrimaryVarsMeaningBrine primaryVarsMeaningBrine() const
|
|
{ return primaryVarsMeaningBrine_; }
|
|
|
|
/*!
|
|
* \brief Set the interpretation which should be applied to the switching primary
|
|
* variables.
|
|
*/
|
|
|
|
void setPrimaryVarsMeaningBrine(PrimaryVarsMeaningBrine newMeaning)
|
|
{ primaryVarsMeaningBrine_ = newMeaning; }
|
|
|
|
/*!
|
|
* \copydoc ImmisciblePrimaryVariables::assignMassConservative
|
|
*/
|
|
template <class FluidState>
|
|
void assignMassConservative(const FluidState& fluidState,
|
|
const MaterialLawParams& matParams,
|
|
bool isInEquilibrium = false)
|
|
{
|
|
using ConstEvaluation = typename std::remove_reference<typename FluidState::Scalar>::type;
|
|
using FsEvaluation = typename std::remove_const<ConstEvaluation>::type;
|
|
using FsToolbox = MathToolbox<FsEvaluation>;
|
|
|
|
#ifndef NDEBUG
|
|
// make sure the temperature is the same in all fluid phases
|
|
for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) {
|
|
Valgrind::CheckDefined(fluidState.temperature(0));
|
|
Valgrind::CheckDefined(fluidState.temperature(phaseIdx));
|
|
|
|
assert(fluidState.temperature(0) == fluidState.temperature(phaseIdx));
|
|
}
|
|
#endif // NDEBUG
|
|
|
|
// for the equilibrium case, we don't need complicated
|
|
// computations.
|
|
if (isInEquilibrium) {
|
|
assignNaive(fluidState);
|
|
return;
|
|
}
|
|
|
|
// If your compiler bails out here, you're probably not using a suitable black
|
|
// oil fluid system.
|
|
typename FluidSystem::template ParameterCache<Scalar> paramCache;
|
|
paramCache.setRegionIndex(pvtRegionIdx_);
|
|
paramCache.setMaxOilSat(FsToolbox::value(fluidState.saturation(oilPhaseIdx)));
|
|
|
|
// create a mutable fluid state with well defined densities based on the input
|
|
using NcpFlash = NcpFlash<Scalar, FluidSystem>;
|
|
using FlashFluidState = CompositionalFluidState<Scalar, FluidSystem>;
|
|
FlashFluidState fsFlash;
|
|
fsFlash.setTemperature(FsToolbox::value(fluidState.temperature(/*phaseIdx=*/0)));
|
|
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
|
fsFlash.setPressure(phaseIdx, FsToolbox::value(fluidState.pressure(phaseIdx)));
|
|
fsFlash.setSaturation(phaseIdx, FsToolbox::value(fluidState.saturation(phaseIdx)));
|
|
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
|
|
fsFlash.setMoleFraction(phaseIdx, compIdx, FsToolbox::value(fluidState.moleFraction(phaseIdx, compIdx)));
|
|
}
|
|
|
|
paramCache.updateAll(fsFlash);
|
|
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
|
if (!FluidSystem::phaseIsActive(phaseIdx))
|
|
continue;
|
|
|
|
Scalar rho = FluidSystem::template density<FlashFluidState, Scalar>(fsFlash, paramCache, phaseIdx);
|
|
fsFlash.setDensity(phaseIdx, rho);
|
|
}
|
|
|
|
// calculate the "global molarities"
|
|
ComponentVector globalMolarities(0.0);
|
|
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
|
|
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
|
if (!FluidSystem::phaseIsActive(phaseIdx))
|
|
continue;
|
|
|
|
globalMolarities[compIdx] +=
|
|
fsFlash.saturation(phaseIdx) * fsFlash.molarity(phaseIdx, compIdx);
|
|
}
|
|
}
|
|
|
|
// use a flash calculation to calculate a fluid state in
|
|
// thermodynamic equilibrium
|
|
|
|
// run the flash calculation
|
|
NcpFlash::template solve<MaterialLaw>(fsFlash, matParams, paramCache, globalMolarities);
|
|
|
|
// use the result to assign the primary variables
|
|
assignNaive(fsFlash);
|
|
}
|
|
|
|
/*!
|
|
* \copydoc ImmisciblePrimaryVariables::assignNaive
|
|
*/
|
|
template <class FluidState>
|
|
void assignNaive(const FluidState& fluidState)
|
|
{
|
|
using ConstEvaluation = typename std::remove_reference<typename FluidState::Scalar>::type;
|
|
using FsEvaluation = typename std::remove_const<ConstEvaluation>::type;
|
|
using FsToolbox = MathToolbox<FsEvaluation>;
|
|
|
|
bool gasPresent = FluidSystem::phaseIsActive(gasPhaseIdx)?(fluidState.saturation(gasPhaseIdx) > 0.0):false;
|
|
bool oilPresent = FluidSystem::phaseIsActive(oilPhaseIdx)?(fluidState.saturation(oilPhaseIdx) > 0.0):false;
|
|
bool waterPresent = FluidSystem::phaseIsActive(waterPhaseIdx)?(fluidState.saturation(waterPhaseIdx) > 0.0):false;
|
|
constexpr const Scalar thresholdWaterFilledCell = 1.0 - 1e-6;
|
|
bool onlyWater = FluidSystem::phaseIsActive(waterPhaseIdx)?(fluidState.saturation(waterPhaseIdx) > thresholdWaterFilledCell):false;
|
|
const auto& saltSaturation = BlackOil::getSaltSaturation_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
bool precipitatedSaltPresent = enableSaltPrecipitation?(saltSaturation > 0.0):false;
|
|
|
|
// deal with the primary variables for the energy extension
|
|
EnergyModule::assignPrimaryVars(*this, fluidState);
|
|
|
|
// determine the meaning of the primary variables
|
|
if (FluidSystem::numActivePhases() == 1) {
|
|
primaryVarsMeaning_ = OnePhase_p;
|
|
}
|
|
else if ((gasPresent && oilPresent) || (onlyWater && FluidSystem::phaseIsActive(oilPhaseIdx))) {
|
|
// gas and oil: both hydrocarbon phases are in equilibrium (i.e., saturated
|
|
// with the "protagonist" component of the other phase.)
|
|
if (FluidSystem::enableVaporizedWater() && !waterPresent)
|
|
primaryVarsMeaning_ = Rvw_po_Sg;
|
|
else
|
|
primaryVarsMeaning_ = Sw_po_Sg;
|
|
}
|
|
else if (oilPresent) {
|
|
// only oil: if dissolved gas is enabled, we need to consider the oil phase
|
|
// composition, if it is disabled, the gas component must stick to its phase
|
|
if (FluidSystem::enableDissolvedGas())
|
|
primaryVarsMeaning_ = Sw_po_Rs;
|
|
else
|
|
primaryVarsMeaning_ = Sw_po_Sg;
|
|
}
|
|
else {
|
|
assert(gasPresent);
|
|
// only gas: if vaporized oil is enabled, we need to consider the gas phase
|
|
// composition, if it is disabled, the oil component must stick to its phase
|
|
if (FluidSystem::enableVaporizedOil())
|
|
primaryVarsMeaning_ = Sw_pg_Rv;
|
|
else if (FluidSystem::enableVaporizedWater() && !waterPresent)
|
|
primaryVarsMeaning_ = Rvw_po_Sg;
|
|
else
|
|
primaryVarsMeaning_ = Sw_po_Sg;
|
|
}
|
|
|
|
if constexpr (enableSaltPrecipitation){
|
|
if (precipitatedSaltPresent)
|
|
primaryVarsMeaningBrine_ = Sp;
|
|
else
|
|
primaryVarsMeaningBrine_ = Cs;
|
|
}
|
|
|
|
// assign the actual primary variables
|
|
if (primaryVarsMeaning() == OnePhase_p) {
|
|
if constexpr (waterEnabled) {
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(waterPhaseIdx));
|
|
} else {
|
|
throw std::logic_error("For single-phase runs, only pure water is presently allowed.");
|
|
}
|
|
}
|
|
else if (primaryVarsMeaning() == Sw_po_Sg) {
|
|
if constexpr (waterEnabled)
|
|
(*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx));
|
|
if constexpr (gasEnabled && waterEnabled && !oilEnabled) {
|
|
//-> water-gas system
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx));
|
|
}
|
|
else if constexpr (oilEnabled) {
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx));
|
|
}
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx));
|
|
}
|
|
else if (primaryVarsMeaning() == Sw_po_Rs) {
|
|
const auto& Rs = BlackOil::getRs_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
|
|
if constexpr (waterEnabled)
|
|
(*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx));
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx));
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[compositionSwitchIdx] = Rs;
|
|
}
|
|
else if (primaryVarsMeaning() == Rvw_po_Sg && FluidSystem::enableVaporizedWater()) {
|
|
const auto& Rvw = BlackOil::getRvw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
if constexpr (waterEnabled)
|
|
(*this)[waterSaturationIdx] = Rvw; //waterSaturationIdx becomes a switching idx
|
|
if constexpr (gasEnabled && waterEnabled && !oilEnabled) {
|
|
//-> water-gas system
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx));
|
|
}
|
|
else if constexpr (oilEnabled) {
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx));
|
|
}
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx));
|
|
}
|
|
else if (primaryVarsMeaning() == Rvw_pg_Rv && FluidSystem::enableVaporizedWater()) {
|
|
const auto& Rvw = BlackOil::getRvw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
const auto& Rv = BlackOil::getRv_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
if constexpr (waterEnabled)
|
|
(*this)[waterSaturationIdx] = Rvw; //waterSaturationIdx becomes a switching idx
|
|
if constexpr (gasEnabled && waterEnabled && !oilEnabled) {
|
|
//-> water-gas system
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx));
|
|
}
|
|
else if constexpr (oilEnabled) {
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx));
|
|
}
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[compositionSwitchIdx] = Rv;
|
|
}
|
|
else {
|
|
assert(primaryVarsMeaning() == Sw_pg_Rv);
|
|
|
|
const auto& Rv = BlackOil::getRv_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
if constexpr (waterEnabled)
|
|
(*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx));
|
|
|
|
(*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx));
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[compositionSwitchIdx] = Rv;
|
|
}
|
|
|
|
if constexpr (enableSaltPrecipitation) {
|
|
if (primaryVarsMeaningBrine() == Sp) {
|
|
(*this)[saltConcentrationIdx] = FsToolbox::value(saltSaturation);
|
|
}
|
|
else {
|
|
const auto& saltConcentration = BlackOil::getSaltConcentration_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
|
|
(*this)[saltConcentrationIdx] = FsToolbox::value(saltConcentration);
|
|
}
|
|
}
|
|
|
|
checkDefined();
|
|
}
|
|
|
|
/*!
|
|
* \brief Adapt the interpretation of the switching variables to be physically
|
|
* meaningful.
|
|
*
|
|
* If the meaning of the primary variables changes, their values are also adapted in a
|
|
* meaningful manner. (e.g. if the gas phase appears and the composition switching
|
|
* variable changes its meaning from the gas dissolution factor Rs to the gas
|
|
* saturation Sg, the value for this variable is set to zero.)
|
|
* A Scalar eps can be passed to make the switching condition more strict.
|
|
* Useful for avoiding ocsilation in the primaryVarsMeaning.
|
|
*
|
|
* \return true Iff the interpretation of one of the switching variables was changed
|
|
*/
|
|
bool adaptPrimaryVariables(const Problem& problem, unsigned globalDofIdx, Scalar eps = 0.0)
|
|
{
|
|
static const Scalar thresholdWaterFilledCell = 1.0 - eps;
|
|
|
|
// this function accesses quite a few black-oil specific low-level functions
|
|
// directly for better performance (instead of going the canonical way through
|
|
// the IntensiveQuantities). The reason is that most intensive quantities are not
|
|
// required to be able to decide if the primary variables needs to be switched or
|
|
// not, so it would be a waste to compute them.
|
|
if (primaryVarsMeaning() == OnePhase_p){
|
|
return false;
|
|
}
|
|
Scalar Sw = 0.0;
|
|
if (waterEnabled && primaryVarsMeaning() != Rvw_po_Sg && primaryVarsMeaning() != Rvw_pg_Rv )
|
|
Sw = (*this)[Indices::waterSaturationIdx];
|
|
|
|
if constexpr (enableSaltPrecipitation) {
|
|
Scalar saltSolubility = BrineModule::saltSol(pvtRegionIndex());
|
|
if (primaryVarsMeaningBrine() == Sp) {
|
|
Scalar saltSat = (*this)[saltConcentrationIdx];
|
|
if (saltSat < -eps){ //precipitated salt dissappears
|
|
setPrimaryVarsMeaningBrine(Cs);
|
|
(*this)[saltConcentrationIdx] = saltSolubility; //set salt concentration to solubility limit
|
|
}
|
|
}
|
|
else if (primaryVarsMeaningBrine() == Cs) {
|
|
Scalar saltConc = (*this)[saltConcentrationIdx];
|
|
if (saltConc > saltSolubility + eps){ //salt concentration exceeds solubility limit
|
|
setPrimaryVarsMeaningBrine(Sp);
|
|
(*this)[saltConcentrationIdx] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
// Primary variable switches possibilities for black-oil (from -> to)
|
|
// Sw_po_Sg (3-phase) -> Rvw_po_Sg, Sw_pg_Rv, Rvw_pg_Rv, Sw_po_Rs
|
|
// Sw_pg_Rv (water-gas) -> Rvw_pg_Rv, Sw_po_Sg, Rvw_po_Sg
|
|
// Rvw_po_Sg (gas-oil) -> Sw_po_Sg, Rvw_pg_Rv
|
|
// Rvw_pg_Rv (gas) -> Sw_pg_Rv, Rvw_po_Sg
|
|
// Sw_po_Rs (water-oil) -> Sw_po_Sg
|
|
if (primaryVarsMeaning() == Sw_po_Sg) {
|
|
|
|
// special case for cells with almost only water
|
|
if (Sw >= thresholdWaterFilledCell) {
|
|
|
|
// make sure water saturations does not exceed 1.0
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx] = 1.0;
|
|
// the hydrocarbon gas saturation is set to 0.0
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[Indices::compositionSwitchIdx] = 0.0;
|
|
|
|
return false;
|
|
}
|
|
|
|
// phase equilibrium, i.e., both hydrocarbon phases are present.
|
|
Scalar Sg = 0.0;
|
|
if constexpr (compositionSwitchEnabled)
|
|
Sg = (*this)[Indices::compositionSwitchIdx];
|
|
|
|
Scalar So = 1.0 - Sw - Sg - solventSaturation_();
|
|
Scalar So3 = 1.0 - Sg - solventSaturation_();
|
|
|
|
//water disappears
|
|
if(Sw < -eps && FluidSystem::enableVaporizedWater()) {
|
|
Scalar pg = 0.0;
|
|
Scalar T = asImp_().temperature_();
|
|
if constexpr (waterEnabled && gasEnabled && !oilEnabled) {
|
|
// twophase water-gas system
|
|
pg = (*this)[Indices::pressureSwitchIdx];
|
|
}
|
|
else {
|
|
if (So3 > 0.0 && Sg > 0.0) {
|
|
// threephase case
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC, So3, Sg + solventSaturation_(), /*Sw=*/ 0.0, matParams);
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
|
|
}
|
|
}
|
|
Scalar RvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg);
|
|
setPrimaryVarsMeaning(Rvw_po_Sg);
|
|
(*this)[Indices::waterSaturationIdx] = RvwSat; //primary variable becomes Rvw
|
|
|
|
return true;
|
|
}
|
|
//water and oil disappears
|
|
if(Sw < -eps && So3 <-eps && Sg > 0.0 && FluidSystem::enableVaporizedWater() && FluidSystem::enableVaporizedOil()) {
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar T = asImp_().temperature_();
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC, /*So*/ 0.0, Sg + solventSaturation_(), /*Sw=*/ 0.0, matParams);
|
|
Scalar pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
|
|
Scalar RvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg);
|
|
|
|
setPrimaryVarsMeaning(Rvw_pg_Rv);
|
|
(*this)[Indices::pressureSwitchIdx] = pg;
|
|
(*this)[Indices::waterSaturationIdx] = RvwSat; //primary variable becomes Rvw
|
|
if constexpr (compositionSwitchEnabled) {
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
|
|
pg,
|
|
zFraction_())
|
|
: FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg,
|
|
Scalar(0),
|
|
SoMax);
|
|
(*this)[Indices::compositionSwitchIdx] = std::min(RvMax, RvSat);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Scalar So2 = 1.0 - Sw - solventSaturation_();
|
|
if (Sg < -eps && So2 > 0.0 && FluidSystem::enableDissolvedGas()) {
|
|
// the hydrocarbon gas phase disappeared and some oil phase is left,
|
|
// i.e., switch the primary variables to { Sw, po, Rs }.
|
|
//
|
|
// by a "lucky" coincidence the pressure switching variable already
|
|
// represents the oil phase pressure, so we do not need to change
|
|
// this. For the gas dissolution factor, we use the low-level blackoil
|
|
// PVT objects to calculate the mole fraction of gas saturated oil.
|
|
setPrimaryVarsMeaning(Sw_po_Rs);
|
|
if constexpr (compositionSwitchEnabled) {
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RsSat = enableExtbo ? ExtboModule::rs(pvtRegionIndex(),
|
|
po,
|
|
zFraction_())
|
|
: FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
|
|
T,
|
|
po,
|
|
So2,
|
|
SoMax);
|
|
(*this)[Indices::compositionSwitchIdx] =
|
|
std::min(RsMax, RsSat);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Scalar Sg2 = 1.0 - Sw - solventSaturation_();
|
|
if (So < -eps && Sg2 > 0.0 && FluidSystem::enableVaporizedOil()) {
|
|
// the oil phase disappeared and some hydrocarbon gas phase is still
|
|
// present, i.e., switch the primary variables to { Sw, pg, Rv }.
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
|
|
// we only have the oil pressure readily available, but we need the gas
|
|
// pressure, i.e. we must determine capillary pressure
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC, /*So=*/0.0, Sg2 + solventSaturation_(), Sw, matParams);
|
|
Scalar pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
|
|
|
|
// we start at the Rv value that corresponds to that of oil-saturated
|
|
// hydrocarbon gas
|
|
setPrimaryVarsMeaning(Sw_pg_Rv);
|
|
(*this)[Indices::pressureSwitchIdx] = pg;
|
|
if constexpr (compositionSwitchEnabled) {
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
|
|
pg,
|
|
zFraction_())
|
|
: FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg,
|
|
Scalar(0),
|
|
SoMax);
|
|
(*this)[Indices::compositionSwitchIdx] = std::min(RvMax, RvSat);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else if (primaryVarsMeaning() == Sw_po_Rs) {
|
|
assert(compositionSwitchEnabled);
|
|
|
|
// special case for cells with almost only water
|
|
if (Sw >= thresholdWaterFilledCell) {
|
|
// switch back to phase equilibrium mode if the oil phase vanishes (i.e.,
|
|
// the water-only case)
|
|
setPrimaryVarsMeaning(Sw_po_Sg);
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx] = 1.0; // water saturation
|
|
|
|
(*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation
|
|
|
|
return true;
|
|
}
|
|
|
|
// Only the oil and the water phases are present. The hydrocarbon gas phase
|
|
// appears as soon as more of the gas component is present in the oil phase
|
|
// than what saturated oil can hold.
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar So = 1.0 - Sw - solventSaturation_();
|
|
Scalar SoMax = std::max(So, problem.maxOilSaturation(globalDofIdx));
|
|
Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RsSat = enableExtbo ? ExtboModule::rs(pvtRegionIndex(),
|
|
po,
|
|
zFraction_())
|
|
: FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
|
|
T,
|
|
po,
|
|
So,
|
|
SoMax);
|
|
|
|
Scalar Rs = (*this)[Indices::compositionSwitchIdx];
|
|
if (Rs > std::min(RsMax, RsSat*(1.0 + eps))) {
|
|
// the gas phase appears, i.e., switch the primary variables to { Sw, po,
|
|
// Sg }.
|
|
setPrimaryVarsMeaning(Sw_po_Sg);
|
|
(*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else if (primaryVarsMeaning() == Rvw_po_Sg) {
|
|
Scalar po = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar Sg = 0.0;
|
|
if constexpr (compositionSwitchEnabled)
|
|
Sg = (*this)[Indices::compositionSwitchIdx];
|
|
|
|
Scalar So = 1.0 - Sg - solventSaturation_();
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC, So, Sg + solventSaturation_(), /*Sw=*/ 0.0, matParams);
|
|
Scalar pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
|
|
Scalar RvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg);
|
|
Scalar Rvw = (*this)[Indices::waterSaturationIdx];
|
|
if (Rvw > RvwSat*(1.0 + eps)) {
|
|
// water phase appears
|
|
setPrimaryVarsMeaning(Sw_po_Sg);
|
|
(*this)[Indices::waterSaturationIdx] = 0.0; // water saturation
|
|
|
|
return true;
|
|
}
|
|
if (So < -eps && FluidSystem::enableVaporizedOil()) {
|
|
//oil phase dissappears
|
|
computeCapillaryPressures_(pC, /*So=*/ 0.0, Sg + solventSaturation_(), /*Sw=*/ 0.0, matParams);
|
|
pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
|
|
setPrimaryVarsMeaning(Rvw_pg_Rv);
|
|
(*this)[Indices::pressureSwitchIdx] = pg;
|
|
if constexpr (compositionSwitchEnabled) {
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
|
|
pg,
|
|
zFraction_())
|
|
: FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg,
|
|
Scalar(0),
|
|
SoMax);
|
|
(*this)[Indices::compositionSwitchIdx] = std::min(RvMax, RvSat);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if (primaryVarsMeaning() == Rvw_pg_Rv) {
|
|
//only gas phase
|
|
Scalar pg = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar RvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg);
|
|
Scalar Rvw = (*this)[Indices::waterSaturationIdx];
|
|
if (Rvw > RvwSat*(1.0 + eps)) {
|
|
// water phase appears
|
|
setPrimaryVarsMeaning(Sw_pg_Rv);
|
|
(*this)[Indices::waterSaturationIdx] = 0.0; // water saturation
|
|
|
|
return true;
|
|
}
|
|
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
|
|
pg,
|
|
zFraction_())
|
|
: FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg,
|
|
/*So=*/Scalar(0.0),
|
|
SoMax);
|
|
|
|
Scalar Rv = (*this)[Indices::compositionSwitchIdx];
|
|
if (Rv > std::min(RvMax, RvSat*(1.0 + eps))) {
|
|
// switch to phase equilibrium mode because the oil phase appears. here
|
|
// we also need the capillary pressures to calculate the oil phase
|
|
// pressure using the gas phase pressure
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC,
|
|
/*So=*/0.0,
|
|
/*Sg=*/1.0,
|
|
/*Sw=*/0.0,
|
|
matParams);
|
|
Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]);
|
|
|
|
setPrimaryVarsMeaning(Rvw_po_Sg);
|
|
(*this)[Indices::pressureSwitchIdx] = po;
|
|
(*this)[Indices::compositionSwitchIdx] = 1.0; // hydrocarbon gas saturation
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else {
|
|
assert(primaryVarsMeaning() == Sw_pg_Rv);
|
|
assert(compositionSwitchEnabled);
|
|
|
|
Scalar T = asImp_().temperature_();
|
|
Scalar pg = (*this)[Indices::pressureSwitchIdx];
|
|
Scalar Sg = 1.0 - Sw - solventSaturation_();
|
|
|
|
// special case for cells with almost only water
|
|
if (Sw >= thresholdWaterFilledCell) {
|
|
// switch to phase equilibrium mode because the hydrocarbon gas phase
|
|
// disappears. here we need the capillary pressures to calculate the oil
|
|
// phase pressure using the gas phase pressure
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC,
|
|
/*So=*/0.0,
|
|
/*Sg=*/Sg + solventSaturation_(),
|
|
Sw,
|
|
matParams);
|
|
Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]);
|
|
|
|
setPrimaryVarsMeaning(Sw_po_Sg);
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx] = 1.0;
|
|
|
|
(*this)[Indices::pressureSwitchIdx] = po;
|
|
(*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation
|
|
|
|
return true;
|
|
}
|
|
|
|
//water disappears
|
|
if(Sw < -eps && FluidSystem::enableVaporizedWater()) {
|
|
Scalar RvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg);
|
|
setPrimaryVarsMeaning(Rvw_pg_Rv);
|
|
(*this)[Indices::waterSaturationIdx] = RvwSat; //primary variable becomes Rvw
|
|
|
|
return true;
|
|
}
|
|
|
|
// Only the gas and the water phases are present. The oil phase appears as
|
|
// soon as more of the oil component is present in the hydrocarbon gas phase
|
|
// than what saturated gas contains. Note that we use the blackoil specific
|
|
// low-level PVT objects here for performance reasons.
|
|
Scalar SoMax = problem.maxOilSaturation(globalDofIdx);
|
|
Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
|
|
Scalar RvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
|
|
pg,
|
|
zFraction_())
|
|
: FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
|
|
T,
|
|
pg,
|
|
/*So=*/Scalar(0.0),
|
|
SoMax);
|
|
|
|
Scalar Rv = (*this)[Indices::compositionSwitchIdx];
|
|
if (Rv > std::min(RvMax, RvSat*(1.0 + eps))) {
|
|
// switch to phase equilibrium mode because the oil phase appears. here
|
|
// we also need the capillary pressures to calculate the oil phase
|
|
// pressure using the gas phase pressure
|
|
std::array<Scalar, numPhases> pC = { 0.0 };
|
|
const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
|
|
computeCapillaryPressures_(pC,
|
|
/*So=*/0.0,
|
|
/*Sg=*/Sg + solventSaturation_(),
|
|
Sw,
|
|
matParams);
|
|
Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]);
|
|
|
|
setPrimaryVarsMeaning(Sw_po_Sg);
|
|
(*this)[Indices::pressureSwitchIdx] = po;
|
|
(*this)[Indices::compositionSwitchIdx] = Sg; // hydrocarbon gas saturation
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
assert(false);
|
|
return false;
|
|
}
|
|
|
|
bool chopAndNormalizeSaturations(){
|
|
if (primaryVarsMeaning() == OnePhase_p){
|
|
return false;
|
|
}
|
|
Scalar Sw = 0.0;
|
|
if (waterEnabled && primaryVarsMeaning() != Rvw_po_Sg)
|
|
Sw = (*this)[Indices::waterSaturationIdx];
|
|
|
|
if (primaryVarsMeaning() == Sw_po_Sg) {
|
|
Scalar Sg = 0.0;
|
|
if constexpr (compositionSwitchEnabled)
|
|
Sg = (*this)[Indices::compositionSwitchIdx];
|
|
Scalar Ssol = 0.0;
|
|
if constexpr (enableSolvent)
|
|
Ssol =(*this) [Indices::solventSaturationIdx];
|
|
|
|
Scalar So = 1.0 - Sw - Sg - Ssol;
|
|
Sw = std::min(std::max(Sw,0.0),1.0);
|
|
So = std::min(std::max(So,0.0),1.0);
|
|
Sg = std::min(std::max(Sg,0.0),1.0);
|
|
Ssol = std::min(std::max(Ssol,0.0),1.0);
|
|
|
|
Scalar St = Sw + So + Sg + Ssol;
|
|
Sw = Sw/St;
|
|
Sg = Sg/St;
|
|
Ssol = Ssol/St;
|
|
assert(St>0.5);
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx]= Sw;
|
|
if constexpr (compositionSwitchEnabled)
|
|
(*this)[Indices::compositionSwitchIdx] = Sg;
|
|
if constexpr (enableSolvent)
|
|
(*this)[Indices::solventSaturationIdx] = Ssol;
|
|
return not(St==1);
|
|
|
|
}else if (primaryVarsMeaning() == Sw_po_Rs) {
|
|
Scalar Ssol = 0.0;
|
|
if constexpr (enableSolvent)
|
|
Ssol = (*this)[Indices::solventSaturationIdx];
|
|
Scalar So = 1.0 - Sw - Ssol;
|
|
Sw = std::min(std::max(Sw,0.0),1.0);
|
|
So = std::min(std::max(So,0.0),1.0);
|
|
Ssol = std::min(std::max(Ssol,0.0),1.0);
|
|
//Sg = 0.0;
|
|
Scalar St = Sw + So + Ssol;
|
|
assert(St>0.5);
|
|
Sw=Sw/St;
|
|
Ssol=Ssol/St;
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx]= Sw;
|
|
if constexpr (enableSolvent)
|
|
(*this)[Indices::solventSaturationIdx] = Ssol;
|
|
return not(St==1);
|
|
}else{
|
|
assert(primaryVarsMeaning() == Sw_pg_Rv);
|
|
assert(compositionSwitchEnabled);
|
|
Scalar Ssol=0.0;
|
|
if constexpr (enableSolvent)
|
|
Ssol = (*this)[Indices::solventSaturationIdx];
|
|
Scalar Sg = 1.0 - Sw - Ssol;
|
|
//So = 0.0;
|
|
Sw = std::min(std::max(Sw,0.0),1.0);
|
|
Sg = std::min(std::max(Sg,0.0),1.0);
|
|
Ssol = std::min(std::max(Ssol,0.0),1.0);
|
|
Scalar St = Sw + Sg + Ssol;
|
|
assert(St>0.5);
|
|
Sw=Sw/St;
|
|
Ssol=Ssol/St;
|
|
if constexpr (waterEnabled)
|
|
(*this)[Indices::waterSaturationIdx]= Sw;
|
|
if constexpr (enableSolvent)
|
|
(*this)[Indices::solventSaturationIdx] = Ssol;
|
|
return not(St==1);
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
BlackOilPrimaryVariables& operator=(const BlackOilPrimaryVariables& other) = default;
|
|
BlackOilPrimaryVariables& operator=(Scalar value)
|
|
{
|
|
for (unsigned i = 0; i < numEq; ++i)
|
|
(*this)[i] = value;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
* \brief Instruct valgrind to check the definedness of all attributes of this class.
|
|
*
|
|
* We cannot simply check the definedness of the whole object because there might be
|
|
* "alignedness holes" in the memory layout which are caused by the pseudo primary
|
|
* variables.
|
|
*/
|
|
void checkDefined() const
|
|
{
|
|
#ifndef NDEBUG
|
|
// check the "real" primary variables
|
|
for (unsigned i = 0; i < this->size(); ++i)
|
|
Valgrind::CheckDefined((*this)[i]);
|
|
|
|
// check the "pseudo" primary variables
|
|
Valgrind::CheckDefined(primaryVarsMeaning_);
|
|
Valgrind::CheckDefined(pvtRegionIdx_);
|
|
#endif // NDEBUG
|
|
}
|
|
|
|
private:
|
|
Implementation& asImp_()
|
|
{ return *static_cast<Implementation*>(this); }
|
|
|
|
const Implementation& asImp_() const
|
|
{ return *static_cast<const Implementation*>(this); }
|
|
|
|
Scalar solventSaturation_() const
|
|
{
|
|
if constexpr (enableSolvent)
|
|
return (*this)[Indices::solventSaturationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar zFraction_() const
|
|
{
|
|
if constexpr (enableExtbo)
|
|
return (*this)[Indices::zFractionIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar polymerConcentration_() const
|
|
{
|
|
if constexpr (enablePolymer)
|
|
return (*this)[Indices::polymerConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar foamConcentration_() const
|
|
{
|
|
if constexpr (enableFoam)
|
|
return (*this)[Indices::foamConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar saltConcentration_() const
|
|
{
|
|
if constexpr (enableBrine)
|
|
return (*this)[Indices::saltConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar temperature_() const
|
|
{
|
|
if constexpr (enableEnergy)
|
|
return (*this)[Indices::temperatureIdx];
|
|
else
|
|
return FluidSystem::reservoirTemperature();
|
|
}
|
|
|
|
Scalar microbialConcentration_() const
|
|
{
|
|
if constexpr (enableMICP)
|
|
return (*this)[Indices::microbialConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar oxygenConcentration_() const
|
|
{
|
|
if constexpr (enableMICP)
|
|
return (*this)[Indices::oxygenConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar ureaConcentration_() const
|
|
{
|
|
if constexpr (enableMICP)
|
|
return (*this)[Indices::ureaConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar biofilmConcentration_() const
|
|
{
|
|
if constexpr (enableMICP)
|
|
return (*this)[Indices::biofilmConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
Scalar calciteConcentration_() const
|
|
{
|
|
if constexpr (enableMICP)
|
|
return (*this)[Indices::calciteConcentrationIdx];
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
template <class Container>
|
|
void computeCapillaryPressures_(Container& result,
|
|
Scalar So,
|
|
Scalar Sg,
|
|
Scalar Sw,
|
|
const MaterialLawParams& matParams) const
|
|
{
|
|
using SatOnlyFluidState = SimpleModularFluidState<Scalar,
|
|
numPhases,
|
|
numComponents,
|
|
FluidSystem,
|
|
/*storePressure=*/false,
|
|
/*storeTemperature=*/false,
|
|
/*storeComposition=*/false,
|
|
/*storeFugacity=*/false,
|
|
/*storeSaturation=*/true,
|
|
/*storeDensity=*/false,
|
|
/*storeViscosity=*/false,
|
|
/*storeEnthalpy=*/false>;
|
|
SatOnlyFluidState fluidState;
|
|
fluidState.setSaturation(waterPhaseIdx, Sw);
|
|
fluidState.setSaturation(oilPhaseIdx, So);
|
|
fluidState.setSaturation(gasPhaseIdx, Sg);
|
|
|
|
MaterialLaw::capillaryPressures(result, matParams, fluidState);
|
|
}
|
|
|
|
PrimaryVarsMeaning primaryVarsMeaning_;
|
|
PrimaryVarsMeaningBrine primaryVarsMeaningBrine_;
|
|
unsigned short pvtRegionIdx_;
|
|
};
|
|
|
|
|
|
} // namespace Opm
|
|
|
|
#endif
|