diff --git a/opm/models/blackoil/blackoilbrinemodules.hh b/opm/models/blackoil/blackoilbrinemodules.hh
new file mode 100644
index 000000000..9a5432c59
--- /dev/null
+++ b/opm/models/blackoil/blackoilbrinemodules.hh
@@ -0,0 +1,425 @@
+// -*- 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 .
+
+ 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
+ *
+ * \brief Contains the classes required to extend the black-oil model by brine.
+ */
+#ifndef EWOMS_BLACK_OIL_BRINE_MODULE_HH
+#define EWOMS_BLACK_OIL_BRINE_MODULE_HH
+
+#include "blackoilproperties.hh"
+#include
+
+#include
+#include
+
+#if HAVE_ECL_INPUT
+#include
+#include
+#include
+#include
+#endif
+
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+namespace Opm {
+/*!
+ * \ingroup BlackOil
+ * \brief Contains the high level supplements required to extend the black oil
+ * model by brine.
+ */
+template
+class BlackOilBrineModule
+{
+ typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+ typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
+ typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
+ typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) IntensiveQuantities;
+ typedef typename GET_PROP_TYPE(TypeTag, ExtensiveQuantities) ExtensiveQuantities;
+ typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
+ typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+ typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
+ typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
+ typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
+ typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
+ typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
+
+ typedef Opm::MathToolbox Toolbox;
+
+ typedef typename Opm::Tabulated1DFunction TabulatedFunction;
+ typedef typename Opm::IntervalTabulated2DFunction TabulatedTwoDFunction;
+
+ static constexpr unsigned saltConcentrationIdx = Indices::saltConcentrationIdx;
+ static constexpr unsigned contiBrineEqIdx = Indices::contiBrineEqIdx;
+ static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
+
+ static constexpr unsigned enableBrine = enableBrineV;
+
+ static constexpr unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq);
+ static constexpr unsigned numPhases = FluidSystem::numPhases;
+
+public:
+
+#if HAVE_ECL_INPUT
+ /*!
+ * \brief Initialize all internal data structures needed by the brine module
+ */
+ static void initFromDeck(const Opm::Deck& deck, const Opm::EclipseState& eclState)
+ {
+ // some sanity checks: if brine are enabled, the BRINE keyword must be
+ // present, if brine are disabled the keyword must not be present.
+ if (enableBrine && !deck.hasKeyword("BRINE")) {
+ throw std::runtime_error("Non-trivial brine treatment requested at compile time, but "
+ "the deck does not contain the BRINE keyword");
+ }
+ else if (!enableBrine && deck.hasKeyword("BRINE")) {
+ throw std::runtime_error("Brine treatment disabled at compile time, but the deck "
+ "contains the BRINE keyword");
+ }
+
+
+ if (!deck.hasKeyword("BRINE"))
+ return; // brine treatment is supposed to be disabled
+
+ const auto& tableManager = eclState.getTableManager();
+
+ unsigned numPvtRegions = tableManager.getTabdims().getNumPVTTables();
+ referencePressure_.resize(numPvtRegions);
+
+ const auto& pvtwsaltTables = tableManager.getPvtwSaltTables();
+
+ // initialize the objects which deal with the BDENSITY keyword
+ const auto& bdensityTables = tableManager.getBrineDensityTables();
+ if (!bdensityTables.empty()) {
+ bdensityTable_.resize(numPvtRegions);
+ assert(numPvtRegions == bdensityTables.size());
+ for (unsigned pvtRegionIdx = 0; pvtRegionIdx < numPvtRegions; ++ pvtRegionIdx) {
+ const auto& bdensityTable = bdensityTables[pvtRegionIdx];
+ const auto& pvtwsaltTable = pvtwsaltTables[pvtRegionIdx];
+ const auto& c = pvtwsaltTable.getSaltConcentrationColumn();
+ const auto& density = bdensityTable.getBrineDensityColumn();
+ bdensityTable_[pvtRegionIdx].setXYContainers(c, density);
+ }
+ }
+ }
+#endif
+
+ /*!
+ * \brief Register all run-time parameters for the black-oil brine module.
+ */
+ static void registerParameters()
+ {
+ if (!enableBrine)
+ // brine have been disabled at compile time
+ return;
+ }
+
+
+ static bool primaryVarApplies(unsigned pvIdx)
+ {
+ if (!enableBrine)
+ // brine have been disabled at compile time
+ return false;
+
+ return pvIdx == saltConcentrationIdx;
+ }
+
+ /*!
+ * \brief Assign the brine specific primary variables to a PrimaryVariables object
+ */
+ template
+ static void assignPrimaryVars(PrimaryVariables& priVars,
+ const FluidState& fluidState)
+ {
+ if (!enableBrine)
+ return;
+
+ priVars[saltConcentrationIdx] = fluidState.saltConcentration();
+ }
+
+ static std::string primaryVarName(unsigned pvIdx)
+ {
+ assert(primaryVarApplies(pvIdx));
+
+ return "saltConcentration";
+ }
+
+ static Scalar primaryVarWeight(unsigned pvIdx OPM_OPTIM_UNUSED)
+ {
+ assert(primaryVarApplies(pvIdx));
+
+ // TODO: it may be beneficial to chose this differently.
+ return static_cast(1.0);
+ }
+
+ static bool eqApplies(unsigned eqIdx)
+ {
+ if (!enableBrine)
+ return false;
+
+ return eqIdx == contiBrineEqIdx;
+ }
+
+ static std::string eqName(unsigned eqIdx)
+ {
+ assert(eqApplies(eqIdx));
+
+ return "conti^brine";
+ }
+
+ static Scalar eqWeight(unsigned eqIdx OPM_OPTIM_UNUSED)
+ {
+ assert(eqApplies(eqIdx));
+
+ // TODO: it may be beneficial to chose this differently.
+ return static_cast(1.0);
+ }
+
+ // must be called after water storage is computed
+ template
+ static void addStorage(Dune::FieldVector& storage,
+ const IntensiveQuantities& intQuants)
+ {
+ if (!enableBrine)
+ return;
+
+ const auto& fs = intQuants.fluidState();
+
+ LhsEval surfaceVolumeWater =
+ Toolbox::template decay(fs.saturation(waterPhaseIdx))
+ * Toolbox::template decay(fs.invB(waterPhaseIdx))
+ * Toolbox::template decay(intQuants.porosity());
+
+ // avoid singular matrix if no water is present.
+ surfaceVolumeWater = Opm::max(surfaceVolumeWater, 1e-10);
+
+ // Brine in water phase
+ const LhsEval massBrine = surfaceVolumeWater
+ * Toolbox::template decay(fs.saltConcentration());
+
+ storage[contiBrineEqIdx] += massBrine;
+ }
+
+ static void computeFlux(RateVector& flux,
+ const ElementContext& elemCtx,
+ unsigned scvfIdx,
+ unsigned timeIdx)
+
+ {
+ if (!enableBrine)
+ return;
+
+ const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
+
+ const unsigned upIdx = extQuants.upstreamIndex(FluidSystem::waterPhaseIdx);
+ const unsigned inIdx = extQuants.interiorIndex();
+ const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
+
+ if (upIdx == inIdx) {
+ flux[contiBrineEqIdx] =
+ extQuants.volumeFlux(waterPhaseIdx)
+ *up.fluidState().invB(waterPhaseIdx)
+ *up.fluidState().saltConcentration();
+ }
+ else {
+ flux[contiBrineEqIdx] =
+ extQuants.volumeFlux(waterPhaseIdx)
+ *Opm::decay(up.fluidState().invB(waterPhaseIdx))
+ *Opm::decay(up.fluidState().saltConcentration());
+ }
+ }
+
+ /*!
+ * \brief Return how much a Newton-Raphson update is considered an error
+ */
+ static Scalar computeUpdateError(const PrimaryVariables& oldPv OPM_OPTIM_UNUSED,
+ const EqVector& delta OPM_OPTIM_UNUSED)
+ {
+ // do not consider consider the cange of Brine primary variables for
+ // convergence
+ // TODO: maybe this should be changed
+ return static_cast(0.0);
+ }
+
+ template
+ static void serializeEntity(const Model& model, std::ostream& outstream, const DofEntity& dof)
+ {
+ if (!enableBrine)
+ return;
+
+ unsigned dofIdx = model.dofMapper().index(dof);
+ const PrimaryVariables& priVars = model.solution(/*timeIdx=*/0)[dofIdx];
+ outstream << priVars[saltConcentrationIdx];
+ }
+
+ template
+ static void deserializeEntity(Model& model, std::istream& instream, const DofEntity& dof)
+ {
+ if (!enableBrine)
+ return;
+
+ unsigned dofIdx = model.dofMapper().index(dof);
+ PrimaryVariables& priVars0 = model.solution(/*timeIdx=*/0)[dofIdx];
+ PrimaryVariables& priVars1 = model.solution(/*timeIdx=*/1)[dofIdx];
+
+ instream >> priVars0[saltConcentrationIdx];
+
+ // set the primary variables for the beginning of the current time step.
+ priVars1[saltConcentrationIdx] = priVars0[saltConcentrationIdx];
+ }
+
+ static const Scalar& referencePressure(const ElementContext& elemCtx,
+ unsigned scvIdx,
+ unsigned timeIdx)
+ {
+ unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
+ return referencePressure_[pvtnumRegionIdx];
+ }
+
+
+ static const TabulatedFunction& bdensityTable(const ElementContext& elemCtx,
+ unsigned scvIdx,
+ unsigned timeIdx)
+ {
+ unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
+ return bdensityTable_[pvtnumRegionIdx];
+ }
+
+ static bool hasBDensityTables()
+ {
+ return !bdensityTable_.empty();
+ }
+
+private:
+ static std::vector bdensityTable_;
+ static std::vector referencePressure_;
+};
+
+
+template
+std::vector::TabulatedFunction>
+BlackOilBrineModule::bdensityTable_;
+
+template
+std::vector::Scalar>
+BlackOilBrineModule::referencePressure_;
+
+/*!
+ * \ingroup BlackOil
+ * \class Ewoms::BlackOilBrineIntensiveQuantities
+ *
+ * \brief Provides the volumetric quantities required for the equations needed by the
+ * brine extension of the black-oil model.
+ */
+template
+class BlackOilBrineIntensiveQuantities
+{
+ typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) Implementation;
+
+ typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+ typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
+ typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
+ typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+ typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
+ typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
+ typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
+
+ typedef BlackOilBrineModule BrineModule;
+
+ enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) };
+ static constexpr int saltConcentrationIdx = Indices::saltConcentrationIdx;
+ static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
+ static constexpr int oilPhaseIdx = FluidSystem::oilPhaseIdx;
+ static constexpr unsigned enableBrine = enableBrineV;
+ static constexpr int contiBrineEqIdx = Indices::contiBrineEqIdx;
+
+public:
+
+ /*!
+ * \brief Update the intensive properties needed to handle brine from the
+ * primary variables
+ *
+ */
+ void updateSaltConcentration_(const ElementContext& elemCtx,
+ unsigned dofIdx,
+ unsigned timeIdx)
+ {
+ const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
+
+ auto& fs = asImp_().fluidState_;
+ // set saltconcentration
+ fs.setSaltConcentration(priVars.makeEvaluation(saltConcentrationIdx, timeIdx));
+
+ }
+
+ const Evaluation& saltConcentration() const
+ { return saltConcentration_; }
+
+ const Evaluation& brineRefDensity() const
+ { return refDensity_; }
+
+protected:
+ Implementation& asImp_()
+ { return *static_cast(this); }
+
+ Evaluation saltConcentration_;
+ Evaluation refDensity_;
+
+};
+
+template
+class BlackOilBrineIntensiveQuantities
+{
+ typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
+ typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
+ typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+
+public:
+ void updateSaltConcentration_(const ElementContext& elemCtx OPM_UNUSED,
+ unsigned dofIdx OPM_UNUSED,
+ unsigned timeIdx OPM_UNUSED)
+ { }
+
+ const Evaluation& saltConcentration() const
+ { throw std::runtime_error("saltConcentration() called but brine are disabled"); }
+
+ const Evaluation& brineRefDensity() const
+ { throw std::runtime_error("brineRefDensity() called but brine are disabled"); }
+
+};
+
+
+
+
+
+} // namespace Ewoms
+
+#endif
diff --git a/opm/models/blackoil/blackoilindices.hh b/opm/models/blackoil/blackoilindices.hh
index 5dcc556dc..53b05cdee 100644
--- a/opm/models/blackoil/blackoilindices.hh
+++ b/opm/models/blackoil/blackoilindices.hh
@@ -35,7 +35,7 @@ namespace Opm {
*
* \brief The primary variable and equation indices for the black-oil model.
*/
-template
+template
struct BlackOilIndices
{
//! Number of phases active at all times
@@ -67,8 +67,11 @@ struct BlackOilIndices
//! Number of foam equations to be considered
static const int numFoam = enableFoam? 1 : 0;
+ //! Number of salt equations to be considered
+ static const int numBrine = enableBrine? 1 : 0;
+
//! The number of equations
- static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam;
+ static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam + numBrine;
//! \brief returns the index of "active" component
static constexpr unsigned canonicalToActiveComponentIndex(unsigned compIdx)
@@ -113,9 +116,13 @@ struct BlackOilIndices
static const int foamConcentrationIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the primary variable for the brine
+ static const int saltConcentrationIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the primary variable for temperature
static const int temperatureIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : - 1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine : - 1000;
////////
@@ -142,10 +149,14 @@ struct BlackOilIndices
static const int contiFoamEqIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the continuity equation for the salt water component
+ static const int contiBrineEqIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the continuity equation for energy
static const int contiEnergyEqIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine: -1000;
};
} // namespace Opm
diff --git a/opm/models/blackoil/blackoilintensivequantities.hh b/opm/models/blackoil/blackoilintensivequantities.hh
index 706393549..047c386b9 100644
--- a/opm/models/blackoil/blackoilintensivequantities.hh
+++ b/opm/models/blackoil/blackoilintensivequantities.hh
@@ -32,6 +32,7 @@
#include "blackoilsolventmodules.hh"
#include "blackoilpolymermodules.hh"
#include "blackoilfoammodules.hh"
+#include "blackoilbrinemodules.hh"
#include "blackoilenergymodules.hh"
#include
#include
@@ -56,6 +57,7 @@ class BlackOilIntensiveQuantities
, public BlackOilSolventIntensiveQuantities
, public BlackOilPolymerIntensiveQuantities
, public BlackOilFoamIntensiveQuantities
+ , public BlackOilBrineIntensiveQuantities
, public BlackOilEnergyIntensiveQuantities
{
typedef typename GET_PROP_TYPE(TypeTag, DiscIntensiveQuantities) ParentType;
@@ -75,6 +77,7 @@ class BlackOilIntensiveQuantities
enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) };
enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) };
enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) };
+ enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) };
enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) };
enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) };
enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) };
@@ -94,7 +97,7 @@ class BlackOilIntensiveQuantities
typedef Opm::MathToolbox Toolbox;
typedef Dune::FieldMatrix DimMatrix;
typedef typename FluxModule::FluxIntensiveQuantities FluxIntensiveQuantities;
- typedef Opm::BlackOilFluidState FluidState;
+ typedef Opm::BlackOilFluidState FluidState;
public:
BlackOilIntensiveQuantities()
@@ -125,6 +128,8 @@ public:
unsigned pvtRegionIdx = priVars.pvtRegionIndex();
fluidState_.setPvtRegionIndex(pvtRegionIdx);
+ asImp_().updateSaltConcentration_(elemCtx, dofIdx, timeIdx);
+
// extract the water and the gas saturations for convenience
Evaluation Sw = 0.0;
if (waterEnabled) {
@@ -444,6 +449,8 @@ private:
friend BlackOilPolymerIntensiveQuantities;
friend BlackOilEnergyIntensiveQuantities;
friend BlackOilFoamIntensiveQuantities;
+ friend BlackOilBrineIntensiveQuantities;
+
Implementation& asImp_()
{ return *static_cast(this); }
diff --git a/opm/models/blackoil/blackoillocalresidual.hh b/opm/models/blackoil/blackoillocalresidual.hh
index 29e87e02e..0f2fece75 100644
--- a/opm/models/blackoil/blackoillocalresidual.hh
+++ b/opm/models/blackoil/blackoillocalresidual.hh
@@ -33,6 +33,7 @@
#include "blackoilpolymermodules.hh"
#include "blackoilenergymodules.hh"
#include "blackoilfoammodules.hh"
+#include "blackoilbrinemodules.hh"
#include
@@ -82,6 +83,7 @@ class BlackOilLocalResidual : public GET_PROP_TYPE(TypeTag, DiscLocalResidual)
typedef BlackOilPolymerModule PolymerModule;
typedef BlackOilEnergyModule EnergyModule;
typedef BlackOilFoamModule FoamModule;
+ typedef BlackOilBrineModule BrineModule;
public:
/*!
@@ -149,6 +151,9 @@ public:
// deal with foam (if present)
FoamModule::addStorage(storage, intQuants);
+
+ // deal with salt (if present)
+ BrineModule::addStorage(storage, intQuants);
}
/*!
@@ -189,6 +194,9 @@ public:
// deal with foam (if present)
FoamModule::computeFlux(flux, elemCtx, scvfIdx, timeIdx);
+
+ // deal with salt (if present)
+ BrineModule::computeFlux(flux, elemCtx, scvfIdx, timeIdx);
}
/*!
diff --git a/opm/models/blackoil/blackoilmodel.hh b/opm/models/blackoil/blackoilmodel.hh
index ec5d8ecca..42ada382c 100644
--- a/opm/models/blackoil/blackoilmodel.hh
+++ b/opm/models/blackoil/blackoilmodel.hh
@@ -44,6 +44,7 @@
#include "blackoilsolventmodules.hh"
#include "blackoilpolymermodules.hh"
#include "blackoilfoammodules.hh"
+#include "blackoilbrinemodules.hh"
#include "blackoildarcyfluxmodule.hh"
#include
@@ -113,6 +114,7 @@ SET_TYPE_PROP(BlackOilModel, Indices,
GET_PROP_VALUE(TypeTag, EnablePolymer),
GET_PROP_VALUE(TypeTag, EnableEnergy),
GET_PROP_VALUE(TypeTag, EnableFoam),
+ GET_PROP_VALUE(TypeTag, EnableBrine),
/*PVOffset=*/0>);
//! Set the fluid system to the black-oil fluid system by default
@@ -131,6 +133,7 @@ SET_BOOL_PROP(BlackOilModel, EnableSolvent, false);
SET_BOOL_PROP(BlackOilModel, EnablePolymer, false);
SET_BOOL_PROP(BlackOilModel, EnablePolymerMW, false);
SET_BOOL_PROP(BlackOilModel, EnableFoam, false);
+SET_BOOL_PROP(BlackOilModel, EnableBrine, false);
//! By default, the blackoil model is isothermal and does not conserve energy
SET_BOOL_PROP(BlackOilModel, EnableTemperature, false);
diff --git a/opm/models/blackoil/blackoilnewtonmethod.hh b/opm/models/blackoil/blackoilnewtonmethod.hh
index e1c63b25b..c9d583853 100644
--- a/opm/models/blackoil/blackoilnewtonmethod.hh
+++ b/opm/models/blackoil/blackoilnewtonmethod.hh
@@ -188,6 +188,7 @@ protected:
static constexpr bool enablePolymerWeight = Indices::polymerMoleWeightIdx >= 0;
static constexpr bool enableEnergy = Indices::temperatureIdx >= 0;
static constexpr bool enableFoam = Indices::foamConcentrationIdx >= 0;
+ static constexpr bool enableBrine = Indices::saltConcentrationIdx >= 0;
currentValue.checkDefined();
Opm::Valgrind::CheckDefined(update);
@@ -289,6 +290,10 @@ protected:
if (enableFoam && pvIdx == Indices::foamConcentrationIdx)
nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0);
+ // keep the salt concentration above 0
+ if (enableBrine && pvIdx == Indices::saltConcentrationIdx)
+ nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0);
+
// keep the temperature above 100 and below 1000 Kelvin
if (enableEnergy && pvIdx == Indices::temperatureIdx)
nextValue[pvIdx] = std::max(std::min(nextValue[pvIdx], 1000.0), 100.0);
diff --git a/opm/models/blackoil/blackoilonephaseindices.hh b/opm/models/blackoil/blackoilonephaseindices.hh
index 531c501ff..58c2754a4 100644
--- a/opm/models/blackoil/blackoilonephaseindices.hh
+++ b/opm/models/blackoil/blackoilonephaseindices.hh
@@ -37,7 +37,7 @@ namespace Opm {
*
* \brief The primary variable and equation indices for the black-oil model.
*/
-template
+template
struct BlackOilOnePhaseIndices
{
//! Is phase enabled or not
@@ -66,11 +66,14 @@ struct BlackOilOnePhaseIndices
//! Number of foam equations to be considered
static const int numFoam = enableFoam? 1 : 0;
+ //! Number of salt equations to be considered
+ static const int numBrine = enableBrine? 1 : 0;
+
//! The number of fluid phases
static const int numPhases = 1;
//! The number of equations
- static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam;
+ static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam + numBrine;
//////////////////////////////
// Primary variable indices
@@ -106,9 +109,13 @@ struct BlackOilOnePhaseIndices
static const int foamConcentrationIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the primary variable for the salt
+ static const int saltConcentrationIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the primary variable for temperature
static const int temperatureIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam: - 1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine: - 1000;
//////////////////////
// Equation indices
@@ -153,9 +160,13 @@ struct BlackOilOnePhaseIndices
static const int contiFoamEqIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the continuity equation for the salt component
+ static const int contiBrineEqIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the continuity equation for energy
static const int contiEnergyEqIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine: -1000;
};
} // namespace Opm
diff --git a/opm/models/blackoil/blackoilprimaryvariables.hh b/opm/models/blackoil/blackoilprimaryvariables.hh
index 9acc4a467..044e17836 100644
--- a/opm/models/blackoil/blackoilprimaryvariables.hh
+++ b/opm/models/blackoil/blackoilprimaryvariables.hh
@@ -33,6 +33,7 @@
#include "blackoilpolymermodules.hh"
#include "blackoilenergymodules.hh"
#include "blackoilfoammodules.hh"
+#include "blackoilbrinemodules.hh"
#include
@@ -51,6 +52,9 @@ class BlackOilSolventModule;
template
class BlackOilPolymerModule;
+template
+class BlackOilBrineModule;
+
/*!
* \ingroup BlackOilModel
*
@@ -92,6 +96,7 @@ class BlackOilPrimaryVariables : public FvBasePrimaryVariables
enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) };
enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) };
enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) };
+ enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) };
enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) };
enum { gasCompIdx = FluidSystem::gasCompIdx };
enum { waterCompIdx = FluidSystem::waterCompIdx };
@@ -103,6 +108,7 @@ class BlackOilPrimaryVariables : public FvBasePrimaryVariables
typedef BlackOilPolymerModule PolymerModule;
typedef BlackOilEnergyModule EnergyModule;
typedef BlackOilFoamModule FoamModule;
+ typedef BlackOilBrineModule BrineModule;
static_assert(numPhases == 3, "The black-oil model assumes three phases!");
static_assert(numComponents == 3, "The black-oil model assumes three components!");
@@ -619,6 +625,14 @@ private:
return (*this)[Indices::foamConcentrationIdx];
}
+ Scalar saltConcentration_() const
+ {
+ if (!enableBrine)
+ return 0.0;
+
+ return (*this)[Indices::saltConcentrationIdx];
+ }
+
Scalar temperature_() const
{
if (!enableEnergy)
diff --git a/opm/models/blackoil/blackoilproperties.hh b/opm/models/blackoil/blackoilproperties.hh
index 88d2bfdbc..56ae6dfa6 100644
--- a/opm/models/blackoil/blackoilproperties.hh
+++ b/opm/models/blackoil/blackoilproperties.hh
@@ -54,6 +54,9 @@ NEW_PROP_TAG(EnablePolymerMW);
NEW_PROP_TAG(BlackoilConserveSurfaceVolume);
//! Enable the ECL-blackoil extension for foam
NEW_PROP_TAG(EnableFoam);
+//! Enable the ECL-blackoil extension for salt
+NEW_PROP_TAG(EnableBrine);
+
//! Allow the spatial and temporal domains to exhibit non-constant temperature
//! in the black-oil model
diff --git a/opm/models/blackoil/blackoilratevector.hh b/opm/models/blackoil/blackoilratevector.hh
index 5e14e2ed7..719e49652 100644
--- a/opm/models/blackoil/blackoilratevector.hh
+++ b/opm/models/blackoil/blackoilratevector.hh
@@ -59,6 +59,7 @@ class BlackOilRateVector
typedef BlackOilSolventModule SolventModule;
typedef BlackOilPolymerModule PolymerModule;
typedef BlackOilFoamModule FoamModule;
+ typedef BlackOilBrineModule BrineModule;
enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) };
@@ -69,6 +70,7 @@ class BlackOilRateVector
enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) };
enum { enablePolymerMolarWeight = GET_PROP_VALUE(TypeTag, EnablePolymerMW) };
enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) };
+ enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) };
typedef Opm::MathToolbox Toolbox;
typedef Dune::FieldVector ParentType;
@@ -139,6 +141,10 @@ public:
throw std::logic_error("setMolarRate() not implemented for foam");
}
+ if ( enableBrine ) {
+ throw std::logic_error("setMolarRate() not implemented for salt water");
+ }
+
// convert to "surface volume" if requested
if (GET_PROP_VALUE(TypeTag, BlackoilConserveSurfaceVolume)) {
if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
diff --git a/opm/models/blackoil/blackoiltwophaseindices.hh b/opm/models/blackoil/blackoiltwophaseindices.hh
index 0346c6c88..df92eca7e 100644
--- a/opm/models/blackoil/blackoiltwophaseindices.hh
+++ b/opm/models/blackoil/blackoiltwophaseindices.hh
@@ -37,7 +37,7 @@ namespace Opm {
*
* \brief The primary variable and equation indices for the black-oil model.
*/
-template
+template
struct BlackOilTwoPhaseIndices
{
//! Is phase enabled or not
@@ -66,11 +66,14 @@ struct BlackOilTwoPhaseIndices
//! Number of foam equations to be considered
static const int numFoam = enableFoam? 1 : 0;
+ //! Number of salt equations to be considered
+ static const int numBrine = enableBrine? 1 : 0;
+
//! The number of fluid phases
static const int numPhases = 2;
//! The number of equations
- static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam;
+ static const int numEq = numPhases + numSolvents + numPolymers + numEnergy + numFoam + numBrine;
//////////////////////////////
// Primary variable indices
@@ -106,9 +109,13 @@ struct BlackOilTwoPhaseIndices
static const int foamConcentrationIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the primary variable for the salt
+ static const int saltConcentrationIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the primary variable for temperature
static const int temperatureIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : - 1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine : - 1000;
//////////////////////
// Equation indices
@@ -171,9 +178,13 @@ struct BlackOilTwoPhaseIndices
static const int contiFoamEqIdx =
enableFoam ? PVOffset + numPhases + numSolvents + numPolymers : -1000;
+ //! Index of the continuity equation for the salt component
+ static const int contiBrineEqIdx =
+ enableBrine ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+
//! Index of the continuity equation for energy
static const int contiEnergyEqIdx =
- enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam : -1000;
+ enableEnergy ? PVOffset + numPhases + numSolvents + numPolymers + numFoam + numBrine : -1000;
};
} // namespace Opm