implemented simple salt/brine option

This commit is contained in:
Trine S. Mykkeltvedt 2019-10-07 12:06:14 +02:00 committed by Tor Harald Sandve
parent 8d5d8ad26c
commit 1841b05b16
7 changed files with 339 additions and 14 deletions

View File

@ -88,6 +88,7 @@ template <class ScalarT,
bool enableTemperature = false,
bool enableEnergy = false,
bool enableDissolution = true,
bool enableSaltWater = false,
unsigned numStoragePhases = FluidSystem::numPhases>
class BlackOilFluidState
{
@ -132,6 +133,10 @@ public:
Opm::Valgrind::CheckDefined(*Rv_);
}
if (enableSaltWater) {
Opm::Valgrind::CheckDefined(*saltconcentration_);
}
if (enableTemperature || enableEnergy)
Opm::Valgrind::CheckDefined(*temperature_);
#endif // NDEBUG
@ -155,6 +160,9 @@ public:
setRv(Opm::BlackOil::getRv_<FluidSystem, FluidState, Scalar>(fs, pvtRegionIdx));
}
if (enableSaltWater){
setSaltconcentration(Opm::BlackOil::getSaltconcentration_<FluidSystem, FluidState, Scalar>(fs, pvtRegionIdx));
}
for (unsigned storagePhaseIdx = 0; storagePhaseIdx < numStoragePhases; ++storagePhaseIdx) {
unsigned phaseIdx = storageToCanonicalPhaseIndex_(storagePhaseIdx);
setSaturation(phaseIdx, fs.saturation(phaseIdx));
@ -243,6 +251,12 @@ public:
void setRv(const Scalar& newRv)
{ *Rv_ = newRv; }
/*!
* \brief Set the salt concentration.
*/
void setSaltconcentration(const Scalar& newSaltconcentration)
{ *saltconcentration_ = newSaltconcentration; }
/*!
* \brief Return the pressure of a fluid phase [Pa]
*/
@ -311,6 +325,19 @@ public:
return *Rv_;
}
/*!
* \brief Return the concentration of salt in water
*/
const Scalar& saltconcentration() const
{
if (!enableSaltWater) {
static Scalar null = 0.0;
return null;
}
return *saltconcentration_;
}
/*!
* \brief Return the PVT region where the current fluid state is assumed to be part of.
*
@ -517,6 +544,7 @@ private:
std::array<Scalar, numStoragePhases> density_;
Opm::ConditionalStorage<enableDissolution,Scalar> Rs_;
Opm::ConditionalStorage<enableDissolution, Scalar> Rv_;
Opm::ConditionalStorage<enableSaltWater, Scalar> saltconcentration_;
unsigned short pvtRegionIdx_;
};

View File

@ -79,6 +79,21 @@ auto getRv_(typename std::enable_if<HasMember_Rv<FluidState>::value, const Fluid
-> decltype(Opm::decay<LhsEval>(fluidState.Rv()))
{ return Opm::decay<LhsEval>(fluidState.Rv()); }
template <class FluidSystem, class FluidState, class LhsEval>
LhsEval getSaltconcentration_(typename std::enable_if<!HasMember_Rs<FluidState>::value, const FluidState&>::type fluidState,
unsigned regionIdx)
{
//const auto& XoG =
// Opm::decay<LhsEval>(fluidState.massFraction(FluidSystem::oilPhaseIdx, FluidSystem::gasCompIdx));
//return FluidSystem::convertXoGToRs(XoG, regionIdx);
}
template <class FluidSystem, class FluidState, class LhsEval>
auto getSaltconcentration_(typename std::enable_if<HasMember_Rs<FluidState>::value, const FluidState&>::type fluidState,
unsigned regionIdx OPM_UNUSED)
-> decltype(Opm::decay<LhsEval>(fluidState.saltconcentration()))
{ return Opm::decay<LhsEval>(fluidState.saltconcentration()); }
}
/*!

View File

@ -0,0 +1,210 @@
// -*- 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::ConstantCompressibilitySaltWaterPvt
*/
#ifndef OPM_CONSTANT_COMPRESSIBILITY_SALTWATER_PVT_HPP
#define OPM_CONSTANT_COMPRESSIBILITY_SALTWATER_PVT_HPP
#include <opm/material/common/Tabulated1DFunction.hpp>
#if HAVE_ECL_INPUT
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/PvtwsaltTable.hpp>
#endif
#include <vector>
namespace Opm {
template <class Scalar, bool enableThermal, bool enableSaltWater>
class WaterPvtMultiplexer;
/*!
* \brief This class represents the Pressure-Volume-Temperature relations of the gas phase
* without vaporized oil.
*/
template <class Scalar>
class ConstantCompressibilitySaltWaterPvt
{
typedef Opm::Tabulated1DFunction<Scalar> TabulatedOneDFunction;
typedef typename Opm::Tabulated1DFunction<Scalar> TabulatedFunction;
typedef std::vector<std::pair<Scalar, Scalar> > SamplingPoints;
public:
#if HAVE_ECL_INPUT
/*!
* \brief Sets the pressure-dependent water viscosity and density
* using a table stemming from the Eclipse PVTWSALT keyword.
*/
void initFromDeck(const Deck& deck, const EclipseState& eclState)
{
const auto& tableManager = eclState.getTableManager();
size_t numRegions = tableManager.getTabdims().getNumPVTTables();
const auto& densityKeyword = deck.getKeyword("DENSITY");
formationVolumeTables_.resize(numRegions);
compressibilityTables_.resize(numRegions);
viscosityTables_.resize(numRegions);
viscosibilityTables_.resize(numRegions);
referencePressure_.resize(numRegions);
const auto& pvtwsaltTables = tableManager.getPvtwSaltTables();
if(!pvtwsaltTables.empty()){
assert(numRegions == pvtwsaltTables.size());
for (unsigned regionIdx = 0; regionIdx < numRegions; ++ regionIdx) {
const auto& pvtwsaltTable = pvtwsaltTables[regionIdx];
const auto& c = pvtwsaltTable.getSaltConcentrationColumn();
const auto& B = pvtwsaltTable.getFormationVolumeFactorColumn();
formationVolumeTables_[regionIdx].setXYContainers(c, B);
const auto& compressibility = pvtwsaltTable.getCompressibilityColumn();
compressibilityTables_[regionIdx].setXYContainers(c, compressibility);
const auto& viscositytable = pvtwsaltTable.getViscosityColumn();
viscosityTables_[regionIdx].setXYContainers(c, viscositytable);
const auto& viscosibility = pvtwsaltTable.getViscosibilityColumn();
viscosibilityTables_[regionIdx].setXYContainers(c, viscosibility);
referencePressure_[regionIdx] = pvtwsaltTable.getReferencePressureValue();
}
}
else {
throw std::runtime_error("PVTWSALT must be specified in SALTWATER runs\n");
}
size_t numPvtwRegions = numRegions;
setNumRegions(numPvtwRegions);
for (unsigned regionIdx = 0; regionIdx < numPvtwRegions; ++ regionIdx) {
auto densityRecord = densityKeyword.getRecord(regionIdx);
waterReferenceDensity_[regionIdx] =
densityRecord.getItem("WATER").getSIDouble(0);
}
initEnd();
}
#endif
void setNumRegions(size_t numRegions)
{
waterReferenceDensity_.resize(numRegions);
for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
setReferenceDensities(regionIdx, 650.0, 1.0, 1000.0);
}
}
/*!
* \brief Set the water reference density [kg / m^3]
*/
void setReferenceDensities(unsigned regionIdx,
Scalar /*rhoRefOil*/,
Scalar /*rhoRefGas*/,
Scalar rhoRefWater)
{ waterReferenceDensity_[regionIdx] = rhoRefWater; }
/*!
* \brief Finish initializing the water phase PVT properties.
*/
void initEnd()
{ }
/*!
* \brief Return the number of PVT regions which are considered by this PVT-object.
*/
unsigned numRegions() const
{ return waterReferenceDensity_.size(); }
/*!
* \brief Returns the specific enthalpy [J/kg] of water given a set of parameters.
*/
template <class Evaluation>
Evaluation internalEnergy(unsigned regionIdx OPM_UNUSED,
const Evaluation& temperature OPM_UNUSED,
const Evaluation& pressure OPM_UNUSED) const
{
throw std::runtime_error("Requested the enthalpy of water but the thermal option is not enabled");
}
/*!
* \brief Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
*/
template <class Evaluation>
Evaluation viscosity(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure,
const Evaluation& saltwaterconcentration) const
{
// cf. ECLiPSE 2013.2 technical description, p. 114
Scalar pRef = referencePressure_[regionIdx];
const Evaluation C = compressibilityTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation Cv = viscosibilityTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation BwRef = formationVolumeTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation Y = (C-Cv)* (pressure - pRef);
Evaluation MuwRef = viscosityTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation& bw = inverseFormationVolumeFactor(regionIdx, temperature, pressure, saltwaterconcentration);
return MuwRef*BwRef*bw/(1 + Y*(1 + Y/2));
}
/*!
* \brief Returns the formation volume factor [-] of the fluid phase.
*/
template <class Evaluation>
Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
const Evaluation& /*temperature*/,
const Evaluation& pressure,
const Evaluation& saltwaterconcentration) const
{
Scalar pRef = referencePressure_[regionIdx];
const Evaluation BwRef = formationVolumeTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation C = compressibilityTables_[regionIdx].eval(saltwaterconcentration, /*extrapolate=*/true);
const Evaluation X = C * (pressure - pRef);
return (1.0 + X*(1.0 + X/2.0))/BwRef;
}
private:
std::vector<TabulatedFunction> formationVolumeTables_;
std::vector<TabulatedFunction> compressibilityTables_;
std::vector<TabulatedFunction> viscosityTables_;
std::vector<TabulatedFunction> viscosibilityTables_;
std::vector<Scalar> referencePressure_;
std::vector<Scalar> waterReferenceDensity_;
};
} // namespace Opm
#endif

View File

@ -184,16 +184,18 @@ public:
throw std::runtime_error("Requested the enthalpy of water but the thermal option is not enabled");
}
/*!
* \brief Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
*/
template <class Evaluation>
Evaluation viscosity(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure) const
const Evaluation& pressure,
const Evaluation& saltconcentration) const
{
Scalar BwMuwRef = waterViscosity_[regionIdx]*waterReferenceFormationVolumeFactor_[regionIdx];
const Evaluation& bw = inverseFormationVolumeFactor(regionIdx, temperature, pressure);
const Evaluation& bw = inverseFormationVolumeFactor(regionIdx, temperature, pressure, saltconcentration);
Scalar pRef = waterReferencePressure_[regionIdx];
const Evaluation& Y =
@ -208,7 +210,8 @@ public:
template <class Evaluation>
Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
const Evaluation& /*temperature*/,
const Evaluation& pressure) const
const Evaluation& pressure,
const Evaluation& /*saltconcentration*/) const
{
// cf. ECLiPSE 2011 technical description, p. 116
Scalar pRef = waterReferencePressure_[regionIdx];

View File

@ -28,6 +28,7 @@
#define OPM_WATER_PVT_MULTIPLEXER_HPP
#include "ConstantCompressibilityWaterPvt.hpp"
#include "ConstantCompressibilitySaltWaterPvt.hpp"
#include "WaterPvtThermal.hpp"
#define OPM_WATER_PVT_MULTIPLEXER_CALL(codeToCall) \
@ -37,6 +38,11 @@
codeToCall; \
break; \
} \
case ConstantCompressibilitySaltWaterPvt: { \
auto& pvtImpl = getRealPvt<ConstantCompressibilitySaltWaterPvt>(); \
codeToCall; \
break; \
} \
case ThermalWaterPvt: { \
auto& pvtImpl = getRealPvt<ThermalWaterPvt>(); \
codeToCall; \
@ -51,7 +57,7 @@ namespace Opm {
* \brief This class represents the Pressure-Volume-Temperature relations of the water
* phase in the black-oil model.
*/
template <class Scalar, bool enableThermal = true>
template <class Scalar, bool enableThermal = true, bool enableSaltWater = true>
class WaterPvtMultiplexer
{
public:
@ -59,6 +65,7 @@ public:
enum WaterPvtApproach {
NoWaterPvt,
ConstantCompressibilitySaltWaterPvt,
ConstantCompressibilityWaterPvt,
ThermalWaterPvt
};
@ -86,6 +93,10 @@ public:
delete &getRealPvt<ConstantCompressibilityWaterPvt>();
break;
}
case ConstantCompressibilitySaltWaterPvt: {
delete &getRealPvt<ConstantCompressibilitySaltWaterPvt>();
break;
}
case ThermalWaterPvt: {
delete &getRealPvt<ThermalWaterPvt>();
break;
@ -111,6 +122,8 @@ public:
setApproach(ThermalWaterPvt);
else if (deck.hasKeyword("PVTW"))
setApproach(ConstantCompressibilityWaterPvt);
else if (enableSaltWater && deck.hasKeyword("PVTWSALT"))
setApproach(ConstantCompressibilitySaltWaterPvt);
OPM_WATER_PVT_MULTIPLEXER_CALL(pvtImpl.initFromDeck(deck, eclState));
}
@ -141,7 +154,37 @@ public:
Evaluation viscosity(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure) const
{ OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.viscosity(regionIdx, temperature, pressure)); return 0; }
{
// assert(realWaterPvt_ != ConstantCompressibilitySaltWaterPvt );
const Evaluation saltconcentration = 0.0;
OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.viscosity(regionIdx, temperature, pressure, saltconcentration));
return 0;
}
/*!
* \brief Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
*/
template <class Evaluation>
Evaluation viscosity(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure,
const Evaluation& saltconcentration) const
{
OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.viscosity(regionIdx, temperature, pressure, saltconcentration));
return 0;
}
/*!
* \brief Returns the formation volume factor [-] of the fluid phase.
*/
template <class Evaluation>
Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure,
const Evaluation& saltconcentration) const
{ OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.inverseFormationVolumeFactor(regionIdx, temperature, pressure, saltconcentration));
return 0;
}
/*!
* \brief Returns the formation volume factor [-] of the fluid phase.
@ -150,7 +193,11 @@ public:
Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure) const
{ OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.inverseFormationVolumeFactor(regionIdx, temperature, pressure)); return 0; }
{
const Evaluation saltconcentration = 0.0;
OPM_WATER_PVT_MULTIPLEXER_CALL(return pvtImpl.inverseFormationVolumeFactor(regionIdx, temperature, pressure, saltconcentration));
return 0;
}
void setApproach(WaterPvtApproach appr)
{
@ -159,6 +206,10 @@ public:
realWaterPvt_ = new Opm::ConstantCompressibilityWaterPvt<Scalar>;
break;
case ConstantCompressibilitySaltWaterPvt:
realWaterPvt_ = new Opm::ConstantCompressibilitySaltWaterPvt<Scalar>;
break;
case ThermalWaterPvt:
realWaterPvt_ = new Opm::WaterPvtThermal<Scalar>;
break;
@ -193,6 +244,20 @@ public:
return *static_cast<Opm::ConstantCompressibilityWaterPvt<Scalar>* >(realWaterPvt_);
}
template <WaterPvtApproach approachV>
typename std::enable_if<approachV == ConstantCompressibilitySaltWaterPvt, Opm::ConstantCompressibilitySaltWaterPvt<Scalar> >::type& getRealPvt()
{
assert(approach() == approachV);
return *static_cast<Opm::ConstantCompressibilitySaltWaterPvt<Scalar>* >(realWaterPvt_);
}
template <WaterPvtApproach approachV>
typename std::enable_if<approachV == ConstantCompressibilitySaltWaterPvt, const Opm::ConstantCompressibilitySaltWaterPvt<Scalar> >::type& getRealPvt() const
{
assert(approach() == approachV);
return *static_cast<Opm::ConstantCompressibilitySaltWaterPvt<Scalar>* >(realWaterPvt_);
}
template <WaterPvtApproach approachV>
typename std::enable_if<approachV == ThermalWaterPvt, Opm::WaterPvtThermal<Scalar> >::type& getRealPvt()
{

View File

@ -42,7 +42,7 @@
#endif
namespace Opm {
template <class Scalar, bool enableThermal>
template <class Scalar, bool enableThermal, bool enableSaltWater>
class WaterPvtMultiplexer;
/*!
@ -56,7 +56,7 @@ class WaterPvtThermal
{
public:
typedef Opm::Tabulated1DFunction<Scalar> TabulatedOneDFunction;
typedef WaterPvtMultiplexer<Scalar, /*enableThermal=*/false> IsothermalPvt;
typedef WaterPvtMultiplexer<Scalar, /*enableThermal=*/false, false> IsothermalPvt;
WaterPvtThermal()
{
@ -269,9 +269,10 @@ public:
template <class Evaluation>
Evaluation viscosity(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure) const
const Evaluation& pressure,
const Evaluation& saltwaterconcentration) const
{
const auto& isothermalMu = isothermalPvt_->viscosity(regionIdx, temperature, pressure);
const auto& isothermalMu = isothermalPvt_->viscosity(regionIdx, temperature, pressure, saltwaterconcentration);
if (!enableThermalViscosity())
return isothermalMu;
@ -289,10 +290,11 @@ public:
template <class Evaluation>
Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
const Evaluation& temperature,
const Evaluation& pressure) const
const Evaluation& pressure,
const Evaluation& saltwaterconcentration) const
{
if (!enableThermalDensity())
return isothermalPvt_->inverseFormationVolumeFactor(regionIdx, temperature, pressure);
return isothermalPvt_->inverseFormationVolumeFactor(regionIdx, temperature, pressure, saltwaterconcentration);
Scalar BwRef = pvtwRefB_[regionIdx];
Scalar TRef = watdentRefTemp_[regionIdx];

View File

@ -247,7 +247,8 @@ inline void testAll()
refTmp = 1.1e-3; // the deck value is given in cP, while the SI units use Pa s...
tmp = constCompWaterPvt.viscosity(/*regionIdx=*/0,
/*temperature=*/273.15 + 20.0,
/*pressure=*/1e5);
/*pressure=*/1e5,
/*saltconcentration=*/0.0);
if (std::abs(tmp - refTmp) > tolerance)
throw std::logic_error("The reference water viscosity at region 0 is supposed to be "+std::to_string(refTmp)
+". (is "+std::to_string(tmp)+")");
@ -255,7 +256,8 @@ inline void testAll()
refTmp = 1.2e-3;
tmp = constCompWaterPvt.viscosity(/*regionIdx=*/1,
/*temperature=*/273.15 + 20.0,
/*pressure=*/2e5);
/*pressure=*/2e5,
/*saltconcentration=*/0.0);
if (std::abs(tmp - refTmp) > tolerance)
throw std::logic_error("The reference water viscosity at region 1 is supposed to be "+std::to_string(refTmp)
+". (is "+std::to_string(tmp)+")");