WIP to make the test_chiflash using TwoPhaseThreeComponentFluidSystem
This commit is contained in:
parent
871bc77ca1
commit
e00be81c90
326
opm/material/fluidsystems/chifluid/ChiParameterCache.hpp
Normal file
326
opm/material/fluidsystems/chifluid/ChiParameterCache.hpp
Normal file
@ -0,0 +1,326 @@
|
||||
// -*- 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::ChiParameterCache
|
||||
*/
|
||||
#ifndef OPM_CHI_PARAMETER_CACHE_HPP
|
||||
#define OPM_CHI_PARAMETER_CACHE_HPP
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <opm/material/components/H2O.hpp>
|
||||
#include <opm/material/fluidsystems/ParameterCacheBase.hpp>
|
||||
|
||||
#include <opm/material/eos/PengRobinson.hpp>
|
||||
#include <opm/material/eos/PengRobinsonParamsMixture.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*!
|
||||
* \ingroup Fluidsystems
|
||||
* \brief Specifies the parameter cache used by the SPE-5 fluid system.
|
||||
*/
|
||||
template <class Scalar, class FluidSystem>
|
||||
class ChiParameterCache
|
||||
: public Opm::ParameterCacheBase<ChiParameterCache<Scalar, FluidSystem> >
|
||||
{
|
||||
using ThisType = ChiParameterCache<Scalar, FluidSystem>;
|
||||
using ParentType = Opm::ParameterCacheBase<ThisType>;
|
||||
using PengRobinson = Opm::PengRobinson<Scalar>;
|
||||
|
||||
enum { numPhases = FluidSystem::numPhases };
|
||||
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
|
||||
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx};
|
||||
|
||||
public:
|
||||
//! The cached parameters for the oil phase
|
||||
using OilPhaseParams = Opm::PengRobinsonParamsMixture<Scalar, FluidSystem, oilPhaseIdx, /*useChi=*/false>;
|
||||
//! The cached parameters for the gas phase
|
||||
using GasPhaseParams = Opm::PengRobinsonParamsMixture<Scalar, FluidSystem, gasPhaseIdx, /*useChi=*/false>;
|
||||
|
||||
ChiParameterCache()
|
||||
{
|
||||
VmUpToDate_[oilPhaseIdx] = false;
|
||||
Valgrind::SetUndefined(Vm_[oilPhaseIdx]);
|
||||
VmUpToDate_[gasPhaseIdx] = false;
|
||||
Valgrind::SetUndefined(Vm_[gasPhaseIdx]);
|
||||
}
|
||||
|
||||
//! \copydoc ParameterCacheBase::updatePhase
|
||||
template <class FluidState>
|
||||
void updatePhase(const FluidState& fluidState,
|
||||
unsigned phaseIdx,
|
||||
int exceptQuantities = ParentType::None)
|
||||
{
|
||||
// if (phaseIdx != oilPhaseIdx)
|
||||
// return;
|
||||
|
||||
updateEosParams(fluidState, phaseIdx, exceptQuantities);
|
||||
|
||||
// if we don't need to recalculate the molar volume, we exit
|
||||
// here
|
||||
// if (VmUpToDate_[phaseIdx])
|
||||
// return;
|
||||
|
||||
// update the phase's molar volume
|
||||
updateMolarVolume_(fluidState, phaseIdx);
|
||||
}
|
||||
|
||||
//! \copydoc ParameterCacheBase::updateSingleMoleFraction
|
||||
template <class FluidState>
|
||||
void updateSingleMoleFraction(const FluidState& fluidState,
|
||||
unsigned phaseIdx,
|
||||
unsigned compIdx)
|
||||
{
|
||||
if (phaseIdx == oilPhaseIdx)
|
||||
oilPhaseParams_.updateSingleMoleFraction(fluidState, compIdx);
|
||||
if (phaseIdx == gasPhaseIdx)
|
||||
gasPhaseParams_.updateSingleMoleFraction(fluidState, compIdx);
|
||||
else
|
||||
return;
|
||||
|
||||
// update the phase's molar volume
|
||||
updateMolarVolume_(fluidState, phaseIdx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The Peng-Robinson attractive parameter for a phase.
|
||||
*
|
||||
* \param phaseIdx The fluid phase of interest
|
||||
*/
|
||||
Scalar a(unsigned phaseIdx) const
|
||||
{
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx: return oilPhaseParams_.a();
|
||||
case gasPhaseIdx: return gasPhaseParams_.a();
|
||||
default:
|
||||
throw std::logic_error("The a() parameter is only defined for "
|
||||
"oil phases");
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The Peng-Robinson covolume for a phase.
|
||||
*
|
||||
* \param phaseIdx The fluid phase of interest
|
||||
*/
|
||||
Scalar b(unsigned phaseIdx) const
|
||||
{
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx: return oilPhaseParams_.b();
|
||||
case gasPhaseIdx: return gasPhaseParams_.b();
|
||||
default:
|
||||
throw std::logic_error("The b() parameter is only defined for "
|
||||
"oil phase");
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The Peng-Robinson attractive parameter for a pure
|
||||
* component given the same temperature and pressure of the
|
||||
* phase.
|
||||
*
|
||||
* \param phaseIdx The fluid phase of interest
|
||||
* \param compIdx The component phase of interest
|
||||
*/
|
||||
Scalar aPure(unsigned phaseIdx, unsigned compIdx) const
|
||||
{
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx: return oilPhaseParams_.pureParams(compIdx).a();
|
||||
case gasPhaseIdx: return gasPhaseParams_.pureParams(compIdx).a();
|
||||
default:
|
||||
throw std::logic_error("The a() parameter is only defined for "
|
||||
"oil phase");
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The Peng-Robinson covolume for a pure component given
|
||||
* the same temperature and pressure of the phase.
|
||||
*
|
||||
* \param phaseIdx The fluid phase of interest
|
||||
* \param compIdx The component phase of interest
|
||||
*/
|
||||
Scalar bPure(unsigned phaseIdx, unsigned compIdx) const
|
||||
{
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx: return oilPhaseParams_.pureParams(compIdx).b();
|
||||
case gasPhaseIdx: return gasPhaseParams_.pureParams(compIdx).b();
|
||||
default:
|
||||
throw std::logic_error("The b() parameter is only defined for "
|
||||
"oil phase");
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the molar volume of a phase [m^3/mol]
|
||||
*
|
||||
* \param phaseIdx The fluid phase of interest
|
||||
*/
|
||||
Scalar molarVolume(unsigned phaseIdx) const
|
||||
{ assert(VmUpToDate_[phaseIdx]); return Vm_[phaseIdx]; }
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Returns the Peng-Robinson mixture parameters for the oil
|
||||
* phase.
|
||||
*/
|
||||
const OilPhaseParams& oilPhaseParams() const
|
||||
{ return oilPhaseParams_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns the Peng-Robinson mixture parameters for the gas
|
||||
* phase.
|
||||
*/
|
||||
const GasPhaseParams& gasPhaseParams() const
|
||||
// { throw std::invalid_argument("gas phase does not exist");}
|
||||
{ return gasPhaseParams_; }
|
||||
|
||||
/*!
|
||||
* \brief Update all parameters required by the equation of state to
|
||||
* calculate some quantities for the phase.
|
||||
*
|
||||
* \param fluidState The representation of the thermodynamic system of interest.
|
||||
* \param phaseIdx The index of the fluid phase of interest.
|
||||
* \param exceptQuantities The quantities of the fluid state that have not changed since the last update.
|
||||
*/
|
||||
template <class FluidState>
|
||||
void updateEosParams(const FluidState& fluidState,
|
||||
unsigned phaseIdx,
|
||||
int exceptQuantities = ParentType::None)
|
||||
{
|
||||
// if (phaseIdx != oilPhaseIdx)
|
||||
// return;
|
||||
|
||||
if (!(exceptQuantities & ParentType::Temperature))
|
||||
{
|
||||
updatePure_(fluidState, phaseIdx);
|
||||
updateMix_(fluidState, phaseIdx);
|
||||
VmUpToDate_[phaseIdx] = false;
|
||||
}
|
||||
else if (!(exceptQuantities & ParentType::Composition))
|
||||
{
|
||||
updateMix_(fluidState, phaseIdx);
|
||||
VmUpToDate_[phaseIdx] = false;
|
||||
}
|
||||
else if (!(exceptQuantities & ParentType::Pressure)) {
|
||||
VmUpToDate_[phaseIdx] = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Update all parameters of a phase which only depend on
|
||||
* temperature and/or pressure.
|
||||
*
|
||||
* This usually means the parameters for the pure components.
|
||||
*/
|
||||
template <class FluidState>
|
||||
void updatePure_(const FluidState& fluidState, unsigned phaseIdx)
|
||||
{
|
||||
Scalar T = fluidState.temperature(phaseIdx);
|
||||
Scalar p = fluidState.pressure(phaseIdx);
|
||||
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx: oilPhaseParams_.updatePure(T, p); break;
|
||||
case gasPhaseIdx: gasPhaseParams_.updatePure(T, p); break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Update all parameters of a phase which depend on the
|
||||
* fluid composition. It is assumed that updatePure() has
|
||||
* been called before this method.
|
||||
*
|
||||
* Here, the mixing rule kicks in.
|
||||
*/
|
||||
template <class FluidState>
|
||||
void updateMix_(const FluidState& fluidState, unsigned phaseIdx)
|
||||
{
|
||||
Valgrind::CheckDefined(fluidState.averageMolarMass(phaseIdx));
|
||||
switch (phaseIdx)
|
||||
{
|
||||
case oilPhaseIdx:
|
||||
oilPhaseParams_.updateMix(fluidState);
|
||||
break;
|
||||
case gasPhaseIdx:
|
||||
gasPhaseParams_.updateMix(fluidState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class FluidState>
|
||||
void updateMolarVolume_(const FluidState& fluidState,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
VmUpToDate_[phaseIdx] = true;
|
||||
|
||||
// calculate molar volume of the phase (we will need this for the
|
||||
// fugacity coefficients and the density anyway)
|
||||
switch (phaseIdx) {
|
||||
case gasPhaseIdx: {
|
||||
// calculate molar volumes for the given composition. although
|
||||
// this isn't a Peng-Robinson parameter strictly speaking, the
|
||||
// molar volume appears in basically every quantity the fluid
|
||||
// system can get queried, so it is okay to calculate it
|
||||
// here...
|
||||
Vm_[gasPhaseIdx] =
|
||||
PengRobinson::computeMolarVolume(fluidState,
|
||||
*this,
|
||||
phaseIdx,
|
||||
/*isGasPhase=*/true);
|
||||
break;
|
||||
}
|
||||
case oilPhaseIdx: {
|
||||
// calculate molar volumes for the given composition. although
|
||||
// this isn't a Peng-Robinson parameter strictly speaking, the
|
||||
// molar volume appears in basically every quantity the fluid
|
||||
// system can get queried, so it is okay to calculate it
|
||||
// here...
|
||||
Vm_[oilPhaseIdx] =
|
||||
PengRobinson::computeMolarVolume(fluidState,
|
||||
*this,
|
||||
phaseIdx,
|
||||
/*isGasPhase=*/false);
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool VmUpToDate_[numPhases];
|
||||
Scalar Vm_[numPhases];
|
||||
|
||||
OilPhaseParams oilPhaseParams_;
|
||||
GasPhaseParams gasPhaseParams_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif
|
212
opm/material/fluidsystems/chifluid/LBCviscosity.hpp
Normal file
212
opm/material/fluidsystems/chifluid/LBCviscosity.hpp
Normal file
@ -0,0 +1,212 @@
|
||||
// -*- 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::LBCviscosity
|
||||
*/
|
||||
|
||||
#ifndef LBC_VISCOSITY_HPP
|
||||
#define LBC_VISCOSITY_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
template <class Scalar, class FluidSystem>
|
||||
class LBCviscosity
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Standard LBC model. (Lohrenz, Bray & Clark: "Calculating Viscosities of Reservoir
|
||||
// fluids from Their Compositions", JPT 16.10 (1964).
|
||||
template <class FluidState, class Params, class LhsEval = typename FluidState::Scalar>
|
||||
static LhsEval LBC(const FluidState& fluidState,
|
||||
const Params& /*paramCache*/,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
const Scalar MPa_atm = 0.101325;
|
||||
const Scalar R = 8.3144598e-3;//Mj/kmol*K
|
||||
const auto& T = Opm::decay<LhsEval>(fluidState.temperature(phaseIdx));
|
||||
const auto& rho = Opm::decay<LhsEval>(fluidState.density(phaseIdx));
|
||||
|
||||
LhsEval sumMm = 0.0;
|
||||
LhsEval sumVolume = 0.0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx) {
|
||||
const Scalar& p_c = FluidSystem::criticalPressure(compIdx)/1e6; // in Mpa;
|
||||
const Scalar& T_c = FluidSystem::criticalTemperature(compIdx);
|
||||
const Scalar Mm = FluidSystem::molarMass(compIdx) * 1000; //in kg/kmol;
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, compIdx));
|
||||
const Scalar v_c = FluidSystem::criticalVolume(compIdx); // in m3/kmol
|
||||
sumMm += x*Mm;
|
||||
sumVolume += x*v_c;
|
||||
}
|
||||
|
||||
LhsEval rho_pc = sumMm/sumVolume; //mixture pseudocritical density
|
||||
LhsEval rho_r = rho/rho_pc;
|
||||
|
||||
|
||||
LhsEval xsum_T_c = 0.0; //mixture pseudocritical temperature
|
||||
LhsEval xsum_Mm = 0.0; //mixture molar mass
|
||||
LhsEval xsum_p_ca = 0.0; //mixture pseudocritical pressure
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx) {
|
||||
const Scalar& p_c = FluidSystem::criticalPressure(compIdx)/1e6; // in Mpa;
|
||||
const Scalar& T_c = FluidSystem::criticalTemperature(compIdx);
|
||||
const Scalar Mm = FluidSystem::molarMass(compIdx) * 1000; //in kg/kmol;
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, compIdx));
|
||||
Scalar p_ca = p_c / MPa_atm;
|
||||
xsum_T_c += x*T_c;
|
||||
xsum_Mm += x*Mm;
|
||||
xsum_p_ca += x*p_ca;
|
||||
}
|
||||
LhsEval zeta_tot = Opm::pow(xsum_T_c / (Opm::pow(xsum_Mm,3.0) * Opm::pow(xsum_p_ca,4.0)),1./6);
|
||||
|
||||
LhsEval my0 = 0.0;
|
||||
LhsEval sumxrM = 0.0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx) {
|
||||
const Scalar& p_c = FluidSystem::criticalPressure(compIdx)/1e6; // in Mpa;
|
||||
const Scalar& T_c = FluidSystem::criticalTemperature(compIdx);
|
||||
const Scalar Mm = FluidSystem::molarMass(compIdx) * 1000; //in kg/kmol;
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, compIdx));
|
||||
Scalar p_ca = p_c / MPa_atm;
|
||||
Scalar zeta = std::pow(T_c / (std::pow(Mm,3.0) * std::pow(p_ca,4.0)),1./6);
|
||||
LhsEval T_r = T/T_c;
|
||||
LhsEval xrM = x * std::pow(Mm,0.5);
|
||||
LhsEval mys = 0.0;
|
||||
if (T_r <=1.5) {
|
||||
mys = 34.0e-5*Opm::pow(T_r,0.94)/zeta;
|
||||
} else {
|
||||
mys = 17.78e-5*Opm::pow(4.58*T_r - 1.67, 0.625)/zeta;
|
||||
}
|
||||
my0 += xrM*mys;
|
||||
sumxrM += xrM;
|
||||
}
|
||||
my0 /= sumxrM;
|
||||
|
||||
std::vector<Scalar> LBC = {0.10230,
|
||||
0.023364,
|
||||
0.058533,
|
||||
-0.040758, // trykkfeil i 1964-artikkel: -0.40758
|
||||
0.0093324};
|
||||
|
||||
LhsEval sumLBC = 0.0;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
sumLBC += Opm::pow(rho_r,i)*LBC[i];
|
||||
}
|
||||
|
||||
return (my0 + (Opm::pow(sumLBC,4.0) - 1e-4)/zeta_tot)/1e3; // mPas-> Pas
|
||||
}
|
||||
|
||||
|
||||
// Improved LBC model for CO2 rich mixtures. (Lansangan, Taylor, Smith & Kovarik - 1993)
|
||||
template <class FluidState, class Params, class LhsEval = typename FluidState::Scalar>
|
||||
static LhsEval LBCmod(const FluidState& fluidState,
|
||||
const Params& /*paramCache*/,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
const Scalar MPa_atm = 0.101325;
|
||||
const Scalar R = 8.3144598e-3;//Mj/kmol*K
|
||||
const auto& T = Opm::decay<LhsEval>(fluidState.temperature(phaseIdx));
|
||||
const auto& rho = Opm::decay<LhsEval>(fluidState.density(phaseIdx));
|
||||
|
||||
LhsEval sumMm = 0.0;
|
||||
LhsEval sumVolume = 0.0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx) {
|
||||
const Scalar& p_c = FluidSystem::criticalPressure(compIdx)/1e6; // in Mpa;
|
||||
const Scalar& T_c = FluidSystem::criticalTemperature(compIdx);
|
||||
const Scalar Mm = FluidSystem::molarMass(compIdx) * 1000; //in kg/kmol;
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, compIdx));
|
||||
const Scalar v_c = FluidSystem::criticalVolume(compIdx); // in m3/kmol
|
||||
sumMm += x*Mm;
|
||||
sumVolume += x*v_c;
|
||||
}
|
||||
|
||||
LhsEval rho_pc = sumMm/sumVolume; //mixture pseudocritical density
|
||||
LhsEval rho_r = rho/rho_pc;
|
||||
|
||||
LhsEval xxT_p = 0.0; // x*x*T_c/p_c
|
||||
LhsEval xxT2_p = 0.0; // x*x*T^2_c/p_c
|
||||
for (unsigned i_compIdx = 0; i_compIdx < FluidSystem::numComponents; ++i_compIdx) {
|
||||
const Scalar& T_c_i = FluidSystem::criticalTemperature(i_compIdx);
|
||||
const Scalar& p_c_i = FluidSystem::criticalPressure(i_compIdx)/1e6; // in Mpa;
|
||||
const auto& x_i = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, i_compIdx));
|
||||
for (unsigned j_compIdx = 0; j_compIdx < FluidSystem::numComponents; ++j_compIdx) {
|
||||
const Scalar& T_c_j = FluidSystem::criticalTemperature(j_compIdx);
|
||||
const Scalar& p_c_j = FluidSystem::criticalPressure(j_compIdx)/1e6; // in Mpa;
|
||||
const auto& x_j = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, j_compIdx));
|
||||
|
||||
const Scalar T_c_ij = std::sqrt(T_c_i*T_c_j);
|
||||
const Scalar p_c_ij = 8.0*T_c_ij / Opm::pow(Opm::pow(T_c_i/p_c_i,1.0/3)+Opm::pow(T_c_j/p_c_j,1.0/3),3);
|
||||
|
||||
xxT_p += x_i*x_j*T_c_ij/p_c_ij;
|
||||
xxT2_p += x_i*x_j*T_c_ij*T_c_ij/p_c_ij;
|
||||
}
|
||||
}
|
||||
|
||||
const LhsEval T_pc = xxT2_p/xxT_p; //mixture pseudocritical temperature
|
||||
const LhsEval p_pc = T_pc/xxT_p; //mixture pseudocritical pressure
|
||||
|
||||
LhsEval p_pca = p_pc / MPa_atm;
|
||||
LhsEval zeta_tot = Opm::pow(T_pc / (Opm::pow(sumMm,3.0) * Opm::pow(p_pca,4.0)),1./6);
|
||||
|
||||
LhsEval my0 = 0.0;
|
||||
LhsEval sumxrM = 0.0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx) {
|
||||
const Scalar& p_c = FluidSystem::criticalPressure(compIdx)/1e6; // in Mpa;
|
||||
const Scalar& T_c = FluidSystem::criticalTemperature(compIdx);
|
||||
const Scalar Mm = FluidSystem::molarMass(compIdx) * 1000; //in kg/kmol;
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, compIdx));
|
||||
Scalar p_ca = p_c / MPa_atm;
|
||||
Scalar zeta = std::pow(T_c / (std::pow(Mm,3.0) * std::pow(p_ca,4.0)),1./6);
|
||||
LhsEval T_r = T/T_c;
|
||||
LhsEval xrM = x * std::pow(Mm,0.5);
|
||||
LhsEval mys = 0.0;
|
||||
if (T_r <=1.5) {
|
||||
mys = 34.0e-5*Opm::pow(T_r,0.94)/zeta;
|
||||
} else {
|
||||
mys = 17.78e-5*Opm::pow(4.58*T_r - 1.67, 0.625)/zeta;
|
||||
}
|
||||
my0 += xrM*mys;
|
||||
sumxrM += xrM;
|
||||
}
|
||||
my0 /= sumxrM;
|
||||
|
||||
std::vector<Scalar> LBC = {0.10230,
|
||||
0.023364,
|
||||
0.058533,
|
||||
-0.040758, // trykkfeil i 1964-artikkel: -0.40758
|
||||
0.0093324};
|
||||
|
||||
LhsEval sumLBC = 0.0;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
sumLBC += Opm::pow(rho_r,i)*LBC[i];
|
||||
}
|
||||
|
||||
return (my0 + (Opm::pow(sumLBC,4.0) - 1e-4)/zeta_tot -1.8366e-8*Opm::pow(rho_r,13.992))/1e3; // mPas-> Pas
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // LBC_VISCOSITY_HPP
|
31
opm/material/fluidsystems/chifluid/chiwoms.h
Normal file
31
opm/material/fluidsystems/chifluid/chiwoms.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __CHIWOMS_H__
|
||||
#define __CHIWOMS_H__
|
||||
|
||||
// values are from the paper "Field-scale implications of density-driven
|
||||
// convection in CO2-EOR reservoirs", to be presented at the Fifth CO2
|
||||
// Geological Storage Workshop, at 21–23 November 2018, in Utrecht,
|
||||
// The Netherlands.
|
||||
|
||||
constexpr double TEMPERATURE = 80; /* degree Celsius */
|
||||
constexpr double GRAVITYFACTOR = 1; /* fraction og gravity */
|
||||
constexpr double MIN_PRES = 75; /* bars */
|
||||
const double MAX_PRES = 220; /* bars */
|
||||
constexpr double SIM_TIME = 1; /* days */
|
||||
constexpr double Y_SIZE = 1.0; /* meter */
|
||||
constexpr double X_SIZE = 1.0; /* meter */
|
||||
constexpr double Z_SIZE = 1.0; /* meter */
|
||||
const unsigned NX = 5; /* number of cells x-dir */
|
||||
const unsigned NY = 5; /* number of cells y-dir */
|
||||
const unsigned NZ = 5; /* number of cells z-dir */
|
||||
const double POROSITY = 0.2; /* non-dimensional */
|
||||
const double PERMEABILITY = 100; /* milli-Darcy */
|
||||
const double DIFFUSIVITY = 1e-9; /* square meter per second */
|
||||
const double MFCOMP0 = 0.9999999;
|
||||
const double MFCOMP1 = 0.0000001;
|
||||
const double MFCOMP2 = 0.0;
|
||||
constexpr double INFLOW_RATE = -1e-4; /* unit kg/s ? */
|
||||
|
||||
/* "random" fields will be equal as long as this is set the same */
|
||||
const double SEED = 5163166242092481088;
|
||||
|
||||
#endif /* __CHIWOMS_H__ */
|
221
opm/material/fluidsystems/chifluid/components.hh
Normal file
221
opm/material/fluidsystems/chifluid/components.hh
Normal file
@ -0,0 +1,221 @@
|
||||
#ifndef COMPONENTS_HH
|
||||
#define COMPONENTS_HH
|
||||
|
||||
#include "chiwoms.h"
|
||||
|
||||
#include <opm/material/IdealGas.hpp>
|
||||
#include <opm/material/components/Component.hpp>
|
||||
#include <opm/material/components/SimpleCO2.hpp>
|
||||
#include <opm/material/components/CO2.hpp>
|
||||
#include <opm/material/components/H2O.hpp>
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup Components
|
||||
*
|
||||
* \brief A simple representation of linear octane
|
||||
*
|
||||
* \tparam Scalar The type used for scalar values
|
||||
*/
|
||||
template <class Scalar>
|
||||
class Octane : public Opm::Component<Scalar, Octane<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "C8"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.11423; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 568.7; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 2.49e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.398; }
|
||||
|
||||
// Critical volume [m3/kmol] (same as [L/mol])
|
||||
static Scalar criticalVolume() {return 4.92e-1; }
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class NDekane : public Opm::Component<Scalar, NDekane<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "C10"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.1423; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 617.7; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 2.103e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.4884; }
|
||||
|
||||
// Critical volume [m3/kmol] (same as [L/mol])
|
||||
static Scalar criticalVolume() {return 6.0976e-1; }
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class Methane : public Opm::Component<Scalar, Methane<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "CH4"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.0160; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 190.5640; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 4.599e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.0114; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 9.8628e-2; }
|
||||
};
|
||||
|
||||
|
||||
template <class Scalar>
|
||||
class Hydrogen : public Opm::Component<Scalar, Hydrogen<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "H2"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.0020156; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 33.2; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 1.297e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return -0.22; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 6.45e-2; }
|
||||
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class Nitrogen : public Opm::Component<Scalar, Nitrogen<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "N2"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.0280134; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 126.192; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 3.3958e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.039; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 8.94e-2; }
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class Water : public Opm::Component<Scalar, Water<Scalar> >
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "H20"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.01801528; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 647; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 22.064e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.344; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 5.595e-2; }
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class ChiwomsCO2 : public Opm::SimpleCO2<Scalar>
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "CO2"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.0440095; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 304.1; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 7.38e6; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.225; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 9.4118e-2; }
|
||||
};
|
||||
|
||||
template <class Scalar>
|
||||
class ChiwomsBrine : public Opm::H2O<Scalar>
|
||||
{
|
||||
public:
|
||||
/// Chemical name
|
||||
static const char* name() { return "H20-NaCl"; }
|
||||
|
||||
/// Molar mass in \f$\mathrm{[kg/mol]}\f$
|
||||
static Scalar molarMass() { return 0.0180158; }
|
||||
|
||||
/// Critical temperature in \f$\mathrm[K]}\f$
|
||||
static Scalar criticalTemperature() { return 647.096; }
|
||||
|
||||
/// Critical pressure in \f$\mathrm[Pa]}\f$
|
||||
static Scalar criticalPressure() { return 2.21e7; }
|
||||
|
||||
/// Acentric factor
|
||||
static Scalar acentricFactor() { return 0.344; }
|
||||
|
||||
// Critical volume [m3/kmol]
|
||||
static Scalar criticalVolume() {return 5.595e-2; }
|
||||
};
|
||||
|
||||
struct EOS
|
||||
{
|
||||
template<typename LhsEval>
|
||||
static LhsEval oleic_enthalpy(LhsEval T, LhsEval p, LhsEval x) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename LhsEval>
|
||||
static LhsEval aqueous_enthalpy(LhsEval T, LhsEval p, LhsEval x) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace opm
|
||||
|
||||
#endif // COMPONENTS_HH
|
360
opm/material/fluidsystems/chifluid/twophasefluidsystem.hh
Normal file
360
opm/material/fluidsystems/chifluid/twophasefluidsystem.hh
Normal file
@ -0,0 +1,360 @@
|
||||
#ifndef TWOPHASEFLUIDSYSTEM_HH
|
||||
#define TWOPHASEFLUIDSYSTEM_HH
|
||||
|
||||
#include "components.hh"
|
||||
#include "chiwoms.h"
|
||||
#include "LBCviscosity.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <stdexcept> // invalid_argument
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <random> // mt19937, normal_distribution
|
||||
#include <limits> // epsilon
|
||||
#include <boost/format.hpp> // boost::format
|
||||
|
||||
#include <opm/common/Exceptions.hpp>
|
||||
#include <opm/material/IdealGas.hpp>
|
||||
|
||||
#include <opm/material/components/Component.hpp>
|
||||
#include <opm/material/components/SimpleCO2.hpp>
|
||||
#include <opm/material/components/CO2.hpp>
|
||||
#include <opm/material/components/Brine.hpp>
|
||||
#include <opm/material/components/SimpleH2O.hpp>
|
||||
#include <opm/material/eos/PengRobinsonMixture.hpp>
|
||||
#include <opm/material/eos/PengRobinsonParamsMixture.hpp>
|
||||
#include "ChiParameterCache.hpp"
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/material/common/Exceptions.hpp>
|
||||
#include <opm/material/common/UniformTabulated2DFunction.hpp>
|
||||
#include <opm/material/common/Unused.hpp>
|
||||
#include <opm/material/fluidsystems/BaseFluidSystem.hpp>
|
||||
#include <opm/material/fluidsystems/NullParameterCache.hpp>
|
||||
#include <opm/material/fluidsystems/H2ON2FluidSystem.hpp>
|
||||
#include <opm/material/fluidsystems/BrineCO2FluidSystem.hpp>
|
||||
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
|
||||
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
|
||||
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
|
||||
|
||||
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
|
||||
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
|
||||
|
||||
#include <opm/material/binarycoefficients/H2O_CO2.hpp>
|
||||
#include <opm/material/binarycoefficients/Brine_CO2.hpp>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
/*!
|
||||
* \ingroup Fluidsystems
|
||||
*
|
||||
* \brief A two-phase fluid system with three components
|
||||
*/
|
||||
template <class Scalar>
|
||||
class TwoPhaseThreeComponentFluidSystem
|
||||
: public Opm::BaseFluidSystem<Scalar, TwoPhaseThreeComponentFluidSystem<Scalar> >
|
||||
{
|
||||
using ThisType = TwoPhaseThreeComponentFluidSystem<Scalar>;
|
||||
using Base = Opm::BaseFluidSystem<Scalar, ThisType>;
|
||||
using PengRobinson = typename Opm::PengRobinson<Scalar>;
|
||||
using PengRobinsonMixture = typename Opm::PengRobinsonMixture<Scalar, ThisType>;
|
||||
using LBCviscosity = typename Opm::LBCviscosity<Scalar, ThisType>;
|
||||
using H2O = typename Opm::H2O<Scalar>;
|
||||
using Brine = typename Opm::Brine<Scalar, H2O>;
|
||||
|
||||
public:
|
||||
//! \copydoc BaseFluidSystem::ParameterCache
|
||||
//template <class Evaluation>
|
||||
//using ParameterCache = Opm::NullParameterCache<Evaluation>;
|
||||
|
||||
//! \copydoc BaseFluidSystem::ParameterCache
|
||||
template <class Evaluation>
|
||||
using ParameterCache = Opm::ChiParameterCache<Evaluation, ThisType>;
|
||||
|
||||
/****************************************
|
||||
* Fluid phase related static parameters
|
||||
****************************************/
|
||||
|
||||
//! \copydoc BaseFluidSystem::numPhases
|
||||
static const int numPhases = 2;
|
||||
|
||||
//! Index of the liquid phase
|
||||
static const int oilPhaseIdx = 0;
|
||||
static const int gasPhaseIdx = 1;
|
||||
|
||||
//! \copydoc BaseFluidSystem::phaseName
|
||||
static const char* phaseName(unsigned phaseIdx)
|
||||
{
|
||||
static const char* name[] = {"o", // oleic phase
|
||||
"g"}; // gas phase
|
||||
|
||||
assert(0 <= phaseIdx && phaseIdx < numPhases);
|
||||
return name[phaseIdx];
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::isIdealMixture
|
||||
static bool isIdealMixture(unsigned phaseIdx)
|
||||
{
|
||||
if (phaseIdx == oilPhaseIdx)
|
||||
return false;
|
||||
|
||||
// CO2 have associative effects
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/****************************************
|
||||
* Component related static parameters
|
||||
****************************************/
|
||||
|
||||
//! \copydoc BaseFluidSystem::numComponents
|
||||
static const int numComponents = 2; // Comp0, Comp1 and Comp2
|
||||
|
||||
//! first comp idx
|
||||
static const int Comp0Idx = 0;
|
||||
|
||||
//! second comp idx
|
||||
static const int Comp1Idx = 1;
|
||||
|
||||
// TODO: make this a loop over choises in chiwoms.hh
|
||||
// using Comp0 = Opm::Methane<Scalar>;
|
||||
using Comp0 = Opm::ChiwomsBrine<Scalar>;
|
||||
using Comp1 = Opm::ChiwomsCO2<Scalar>;
|
||||
|
||||
static void init(Scalar minT = 273.15,
|
||||
Scalar maxT = 373.15,
|
||||
Scalar minP = 1e4,
|
||||
Scalar maxP = 100e6)
|
||||
{
|
||||
Opm::PengRobinsonParamsMixture<Scalar, ThisType, oilPhaseIdx, /*useSpe5=*/false> prParams;
|
||||
|
||||
// find envelopes of the 'a' and 'b' parameters for the range
|
||||
// minT <= T <= maxT and minP <= p <= maxP. For
|
||||
// this we take advantage of the fact that 'a' and 'b' for
|
||||
// mixtures is just a convex combination of the attractive and
|
||||
// repulsive parameters of the pure components
|
||||
|
||||
Scalar minA = 1e30, maxA = -1e30;
|
||||
Scalar minB = 1e30, maxB = -1e30;
|
||||
|
||||
prParams.updatePure(minT, minP);
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
minA = std::min(prParams.pureParams(compIdx).a(), minA);
|
||||
maxA = std::max(prParams.pureParams(compIdx).a(), maxA);
|
||||
minB = std::min(prParams.pureParams(compIdx).b(), minB);
|
||||
maxB = std::max(prParams.pureParams(compIdx).b(), maxB);
|
||||
};
|
||||
|
||||
prParams.updatePure(maxT, minP);
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
minA = std::min(prParams.pureParams(compIdx).a(), minA);
|
||||
maxA = std::max(prParams.pureParams(compIdx).a(), maxA);
|
||||
minB = std::min(prParams.pureParams(compIdx).b(), minB);
|
||||
maxB = std::max(prParams.pureParams(compIdx).b(), maxB);
|
||||
};
|
||||
|
||||
prParams.updatePure(minT, maxP);
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
minA = std::min(prParams.pureParams(compIdx).a(), minA);
|
||||
maxA = std::max(prParams.pureParams(compIdx).a(), maxA);
|
||||
minB = std::min(prParams.pureParams(compIdx).b(), minB);
|
||||
maxB = std::max(prParams.pureParams(compIdx).b(), maxB);
|
||||
};
|
||||
|
||||
prParams.updatePure(maxT, maxP);
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
|
||||
minA = std::min(prParams.pureParams(compIdx).a(), minA);
|
||||
maxA = std::max(prParams.pureParams(compIdx).a(), maxA);
|
||||
minB = std::min(prParams.pureParams(compIdx).b(), minB);
|
||||
maxB = std::max(prParams.pureParams(compIdx).b(), maxB);
|
||||
};
|
||||
// PengRobinson::init(/*aMin=*/minA, /*aMax=*/maxA, /*na=*/100,
|
||||
// /*bMin=*/minB, /*bMax=*/maxB, /*nb=*/200);
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::componentName
|
||||
static const char* componentName(unsigned compIdx)
|
||||
{
|
||||
static const char* name[] = {
|
||||
Comp0::name(),
|
||||
Comp1::name(),
|
||||
};
|
||||
|
||||
assert(0 <= compIdx && compIdx < numComponents);
|
||||
return name[compIdx];
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::molarMass
|
||||
static Scalar molarMass(unsigned compIdx)
|
||||
{
|
||||
return (compIdx == Comp0Idx)
|
||||
? Comp0::molarMass()
|
||||
: (compIdx == Comp1Idx)
|
||||
? Comp1::molarMass()
|
||||
: throw std::invalid_argument("Molar mass component index");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Critical temperature of a component [K].
|
||||
*
|
||||
* \copydetails Doxygen::compIdxParam
|
||||
*/
|
||||
static Scalar criticalTemperature(unsigned compIdx)
|
||||
{
|
||||
return (compIdx == Comp0Idx)
|
||||
? Comp0::criticalTemperature()
|
||||
: (compIdx == Comp1Idx)
|
||||
? Comp1::criticalTemperature()
|
||||
: throw std::invalid_argument("Critical temperature component index");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Critical pressure of a component [Pa].
|
||||
*
|
||||
* \copydetails Doxygen::compIdxParam
|
||||
*/
|
||||
static Scalar criticalPressure(unsigned compIdx)
|
||||
{
|
||||
return (compIdx == Comp0Idx)
|
||||
? Comp0::criticalPressure()
|
||||
: (compIdx == Comp1Idx)
|
||||
? Comp1::criticalPressure()
|
||||
: throw std::invalid_argument("Critical pressure component index");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Critical volume of a component [m3].
|
||||
*
|
||||
* \copydetails Doxygen::compIdxParam
|
||||
*/
|
||||
static Scalar criticalVolume(unsigned compIdx)
|
||||
{
|
||||
return (compIdx == Comp0Idx)
|
||||
? Comp0::criticalVolume()
|
||||
: (compIdx == Comp1Idx)
|
||||
? Comp1::criticalVolume()
|
||||
: throw std::invalid_argument("Critical volume component index");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The acentric factor of a component [].
|
||||
*
|
||||
* \copydetails Doxygen::compIdxParam
|
||||
*/
|
||||
static Scalar acentricFactor(unsigned compIdx)
|
||||
{
|
||||
return (compIdx == Comp0Idx)
|
||||
? Comp0::acentricFactor()
|
||||
: (compIdx == Comp1Idx)
|
||||
? Comp1::acentricFactor()
|
||||
: throw std::invalid_argument("Molar mass component index");
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* thermodynamic relations
|
||||
****************************************/
|
||||
|
||||
/*!
|
||||
* \copydoc BaseFluidSystem::density
|
||||
*/
|
||||
template <class FluidState, class LhsEval = typename FluidState::Scalar, class ParamCacheEval = LhsEval>
|
||||
static LhsEval density(const FluidState& fluidState,
|
||||
const ParameterCache<ParamCacheEval>& paramCache,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
|
||||
LhsEval dens;
|
||||
if (phaseIdx == oilPhaseIdx || phaseIdx == gasPhaseIdx) {
|
||||
// paramCache.updatePhase(fluidState, phaseIdx);
|
||||
dens = fluidState.averageMolarMass(phaseIdx) / paramCache.molarVolume(phaseIdx);
|
||||
}
|
||||
return dens;
|
||||
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::viscosity
|
||||
template <class FluidState, class LhsEval = typename FluidState::Scalar, class ParamCacheEval = LhsEval>
|
||||
static LhsEval viscosity(const FluidState& fluidState,
|
||||
const ParameterCache<ParamCacheEval>& paramCache,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
// Use LBC method to calculate viscosity
|
||||
LhsEval mu;
|
||||
// if (phaseIdx == gasPhaseIdx) {
|
||||
mu = LBCviscosity::LBCmod(fluidState, paramCache, phaseIdx);
|
||||
// }
|
||||
// else {
|
||||
// const auto& T = Opm::decay<LhsEval>(fluidState.temperature(phaseIdx));
|
||||
// const auto& p = Opm::decay<LhsEval>(fluidState.pressure(0));
|
||||
// mu = Brine::liquidViscosity(T, p);
|
||||
// }
|
||||
return mu;
|
||||
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::enthalpy
|
||||
template <class FluidState, class LhsEval = typename FluidState::Scalar, class ParamCacheEval = LhsEval>
|
||||
static LhsEval enthalpy(const FluidState& fluidState,
|
||||
const ParameterCache<ParamCacheEval>& /*paramCache*/,
|
||||
unsigned phaseIdx)
|
||||
{
|
||||
const auto& T = Opm::decay<LhsEval>(fluidState.temperature(phaseIdx));
|
||||
const auto& p = Opm::decay<LhsEval>(fluidState.pressure(phaseIdx));
|
||||
const auto& x = Opm::decay<LhsEval>(fluidState.moleFraction(phaseIdx, Comp1Idx));
|
||||
|
||||
if(phaseIdx == oilPhaseIdx) {
|
||||
return EOS::oleic_enthalpy(T, p, x); //TODO
|
||||
}
|
||||
else {
|
||||
return EOS::aqueous_enthalpy(T, p, x); //TODO
|
||||
}
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::fugacityCoefficient
|
||||
template <class FluidState, class LhsEval = typename FluidState::Scalar, class ParamCacheEval = LhsEval>
|
||||
static LhsEval fugacityCoefficient(const FluidState& fluidState,
|
||||
const ParameterCache<ParamCacheEval>& paramCache,
|
||||
unsigned phaseIdx,
|
||||
unsigned compIdx)
|
||||
{
|
||||
assert(0 <= phaseIdx && phaseIdx < numPhases);
|
||||
assert(0 <= compIdx && compIdx < numComponents);
|
||||
|
||||
Scalar phi = Opm::getValue(
|
||||
PengRobinsonMixture::computeFugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx));
|
||||
return phi;
|
||||
|
||||
|
||||
throw std::invalid_argument("crap!");
|
||||
}
|
||||
|
||||
//! \copydoc BaseFluidSystem::diffusionCoefficient
|
||||
template <class FluidState, class LhsEval = typename FluidState::Scalar, class ParamCacheEval = LhsEval>
|
||||
static LhsEval diffusionCoefficient(const FluidState& /*fluidState*/,
|
||||
const ParameterCache<ParamCacheEval>& /*paramCache*/,
|
||||
unsigned /*phaseIdx*/,
|
||||
unsigned /*compIdx*/)
|
||||
{
|
||||
return DIFFUSIVITY;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the interaction coefficient for two components.
|
||||
*.
|
||||
*/
|
||||
static Scalar interactionCoefficient(unsigned comp1Idx, unsigned comp2Idx)
|
||||
{
|
||||
return 0.0; //-0.101;//0.1089;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};//namespace opm
|
||||
|
||||
#endif // TWOPHASEFLUIDSYSTEM_HH
|
@ -29,6 +29,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <opm/material/constraintsolvers/ChiFlash.hpp>
|
||||
#include <opm/material/fluidsystems/chifluid/twophasefluidsystem.hh>
|
||||
|
||||
#include <opm/material/densead/Evaluation.hpp>
|
||||
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
|
||||
@ -40,471 +41,15 @@
|
||||
|
||||
#include <dune/common/parallel/mpihelper.hh>
|
||||
|
||||
template <class FluidSystem, class FluidState>
|
||||
void createSurfaceGasFluidSystem(FluidState& gasFluidState)
|
||||
{
|
||||
static const int gasPhaseIdx = FluidSystem::gasPhaseIdx;
|
||||
|
||||
// temperature
|
||||
gasFluidState.setTemperature(273.15 + 20);
|
||||
|
||||
// gas pressure
|
||||
gasFluidState.setPressure(gasPhaseIdx, 1e5);
|
||||
|
||||
// gas saturation
|
||||
gasFluidState.setSaturation(gasPhaseIdx, 1.0);
|
||||
|
||||
// gas composition: mostly methane, a bit of propane
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::H2OIdx, 0.0);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C1Idx, 0.94);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C3Idx, 0.06);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C6Idx, 0.00);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C10Idx, 0.00);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C15Idx, 0.00);
|
||||
gasFluidState.setMoleFraction(gasPhaseIdx, FluidSystem::C20Idx, 0.00);
|
||||
|
||||
// gas density
|
||||
typename FluidSystem::template ParameterCache<typename FluidState::Scalar> paramCache;
|
||||
paramCache.updatePhase(gasFluidState, gasPhaseIdx);
|
||||
gasFluidState.setDensity(gasPhaseIdx,
|
||||
FluidSystem::density(gasFluidState, paramCache, gasPhaseIdx));
|
||||
}
|
||||
|
||||
template <class Scalar, class FluidSystem, class FluidState>
|
||||
Scalar computeSumxg(FluidState& resultFluidState,
|
||||
const FluidState& prestineFluidState,
|
||||
const FluidState& gasFluidState,
|
||||
Scalar additionalGas)
|
||||
{
|
||||
static const int oilPhaseIdx = FluidSystem::oilPhaseIdx;
|
||||
static const int gasPhaseIdx = FluidSystem::gasPhaseIdx;
|
||||
static const int numComponents = FluidSystem::numComponents;
|
||||
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
typedef Opm::NcpFlash<Scalar, FluidSystem> Flash;
|
||||
|
||||
resultFluidState.assign(prestineFluidState);
|
||||
|
||||
// add a bit of additional gas components
|
||||
ComponentVector totalMolarities;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++ compIdx)
|
||||
totalMolarities =
|
||||
prestineFluidState.molarity(oilPhaseIdx, compIdx)
|
||||
+ additionalGas*gasFluidState.moleFraction(gasPhaseIdx, compIdx);
|
||||
|
||||
// "flash" the modified fluid state
|
||||
typename FluidSystem::ParameterCache paramCache;
|
||||
Flash::solve(resultFluidState, totalMolarities);
|
||||
|
||||
Scalar sumxg = 0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx)
|
||||
sumxg += resultFluidState.moleFraction(gasPhaseIdx, compIdx);
|
||||
|
||||
return sumxg;
|
||||
}
|
||||
|
||||
template <class Scalar, class FluidSystem, class FluidState>
|
||||
void makeOilSaturated(FluidState& fluidState, const FluidState& gasFluidState)
|
||||
{
|
||||
static const int gasPhaseIdx = FluidSystem::gasPhaseIdx;
|
||||
|
||||
FluidState prestineFluidState;
|
||||
prestineFluidState.assign(fluidState);
|
||||
|
||||
Scalar sumxg = 0;
|
||||
for (unsigned compIdx = 0; compIdx < FluidSystem::numComponents; ++compIdx)
|
||||
sumxg += fluidState.moleFraction(gasPhaseIdx, compIdx);
|
||||
|
||||
// Newton method
|
||||
Scalar tol = 1e-8;
|
||||
Scalar additionalGas = 0; // [mol]
|
||||
for (int i = 0; std::abs(sumxg - 1) > tol; ++i) {
|
||||
if (i > 50)
|
||||
throw std::runtime_error("Newton method did not converge after 50 iterations");
|
||||
|
||||
Scalar eps = std::max(1e-8, additionalGas*1e-8);
|
||||
|
||||
Scalar f = 1 - computeSumxg<Scalar, FluidSystem>(prestineFluidState,
|
||||
fluidState,
|
||||
gasFluidState,
|
||||
additionalGas);
|
||||
Scalar fStar = 1 - computeSumxg<Scalar, FluidSystem>(prestineFluidState,
|
||||
fluidState,
|
||||
gasFluidState,
|
||||
additionalGas + eps);
|
||||
Scalar fPrime = (fStar - f)/eps;
|
||||
|
||||
additionalGas -= f/fPrime;
|
||||
};
|
||||
}
|
||||
|
||||
template <class FluidSystem, class FluidState>
|
||||
void guessInitial(FluidState& fluidState, unsigned phaseIdx)
|
||||
{
|
||||
if (phaseIdx == FluidSystem::gasPhaseIdx) {
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::H2OIdx, 0.0);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C1Idx, 0.74785);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C3Idx, 0.0121364);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C6Idx, 0.00606028);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C10Idx, 0.00268136);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C15Idx, 0.000204256);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C20Idx, 8.78291e-06);
|
||||
}
|
||||
else if (phaseIdx == FluidSystem::oilPhaseIdx) {
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::H2OIdx, 0.0);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C1Idx, 0.50);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C3Idx, 0.03);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C6Idx, 0.07);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C10Idx, 0.20);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C15Idx, 0.15);
|
||||
fluidState.setMoleFraction(phaseIdx, FluidSystem::C20Idx, 0.05);
|
||||
}
|
||||
else {
|
||||
assert(phaseIdx == FluidSystem::waterPhaseIdx);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Scalar, class FluidSystem, class FluidState>
|
||||
Scalar bringOilToSurface(FluidState& surfaceFluidState, Scalar alpha, const FluidState& reservoirFluidState, bool guessInitial)
|
||||
{
|
||||
enum {
|
||||
numPhases = FluidSystem::numPhases,
|
||||
waterPhaseIdx = FluidSystem::waterPhaseIdx,
|
||||
gasPhaseIdx = FluidSystem::gasPhaseIdx,
|
||||
oilPhaseIdx = FluidSystem::oilPhaseIdx,
|
||||
|
||||
numComponents = FluidSystem::numComponents
|
||||
};
|
||||
|
||||
typedef Opm::NcpFlash<Scalar, FluidSystem> Flash;
|
||||
typedef Opm::ThreePhaseMaterialTraits<Scalar, waterPhaseIdx, oilPhaseIdx, gasPhaseIdx> MaterialTraits;
|
||||
typedef Opm::LinearMaterial<MaterialTraits> MaterialLaw;
|
||||
typedef typename MaterialLaw::Params MaterialLawParams;
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
|
||||
const Scalar refPressure = 1.0135e5; // [Pa]
|
||||
|
||||
// set the parameters for the capillary pressure law
|
||||
MaterialLawParams matParams;
|
||||
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
matParams.setPcMinSat(phaseIdx, 0.0);
|
||||
matParams.setPcMaxSat(phaseIdx, 0.0);
|
||||
}
|
||||
matParams.finalize();
|
||||
|
||||
// retieve the global volumetric component molarities
|
||||
surfaceFluidState.setTemperature(273.15 + 20);
|
||||
|
||||
ComponentVector molarities;
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx)
|
||||
molarities[compIdx] = reservoirFluidState.molarity(oilPhaseIdx, compIdx);
|
||||
|
||||
if (guessInitial) {
|
||||
// we start at a fluid state with reservoir oil.
|
||||
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx) {
|
||||
surfaceFluidState.setMoleFraction(phaseIdx,
|
||||
compIdx,
|
||||
reservoirFluidState.moleFraction(phaseIdx, compIdx));
|
||||
}
|
||||
surfaceFluidState.setDensity(phaseIdx, reservoirFluidState.density(phaseIdx));
|
||||
surfaceFluidState.setPressure(phaseIdx, reservoirFluidState.pressure(phaseIdx));
|
||||
surfaceFluidState.setSaturation(phaseIdx, 0.0);
|
||||
}
|
||||
surfaceFluidState.setSaturation(oilPhaseIdx, 1.0);
|
||||
surfaceFluidState.setSaturation(gasPhaseIdx, 1.0 - surfaceFluidState.saturation(oilPhaseIdx));
|
||||
}
|
||||
|
||||
typename FluidSystem::template ParameterCache<Scalar> paramCache;
|
||||
paramCache.updateAll(surfaceFluidState);
|
||||
|
||||
// increase volume until we are at surface pressure. use the
|
||||
// newton method for this
|
||||
ComponentVector tmpMolarities;
|
||||
for (int i = 0;; ++i) {
|
||||
if (i >= 20)
|
||||
throw Opm::NumericalIssue("Newton method did not converge after 20 iterations");
|
||||
|
||||
// calculate the deviation from the standard pressure
|
||||
tmpMolarities = molarities;
|
||||
tmpMolarities /= alpha;
|
||||
Flash::template solve<MaterialLaw>(surfaceFluidState, matParams, paramCache, tmpMolarities);
|
||||
Scalar f = surfaceFluidState.pressure(gasPhaseIdx) - refPressure;
|
||||
|
||||
// calculate the derivative of the deviation from the standard
|
||||
// pressure
|
||||
Scalar eps = alpha*1e-10;
|
||||
tmpMolarities = molarities;
|
||||
tmpMolarities /= alpha + eps;
|
||||
Flash::template solve<MaterialLaw>(surfaceFluidState, matParams, paramCache, tmpMolarities);
|
||||
Scalar fStar = surfaceFluidState.pressure(gasPhaseIdx) - refPressure;
|
||||
Scalar fPrime = (fStar - f)/eps;
|
||||
|
||||
// newton update
|
||||
Scalar delta = f/fPrime;
|
||||
alpha -= delta;
|
||||
if (std::abs(delta) < std::abs(alpha)*1e-9) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the final result
|
||||
tmpMolarities = molarities;
|
||||
tmpMolarities /= alpha;
|
||||
Flash::template solve<MaterialLaw>(surfaceFluidState, matParams, paramCache, tmpMolarities);
|
||||
return alpha;
|
||||
}
|
||||
|
||||
template <class RawTable>
|
||||
void printResult(const RawTable& rawTable,
|
||||
const std::string& fieldName,
|
||||
size_t firstIdx,
|
||||
size_t secondIdx,
|
||||
double hiresThres)
|
||||
{
|
||||
std::cout << "std::vector<std::pair<Scalar, Scalar> > "<<fieldName<<" = {\n";
|
||||
|
||||
size_t sampleIdx = 0;
|
||||
size_t numSamples = 20;
|
||||
size_t numRawHires = 0;
|
||||
for (; rawTable[numRawHires][firstIdx] > hiresThres; ++numRawHires)
|
||||
{}
|
||||
|
||||
for (; sampleIdx < numSamples; ++sampleIdx) {
|
||||
size_t rawIdx = sampleIdx*numRawHires/numSamples;
|
||||
std::cout << "{ " << rawTable[rawIdx][firstIdx] << ", "
|
||||
<< rawTable[rawIdx][secondIdx] << " }"
|
||||
<< ",\n";
|
||||
}
|
||||
|
||||
numSamples = 15;
|
||||
for (sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) {
|
||||
size_t rawIdx = sampleIdx*(rawTable.size() - numRawHires)/numSamples + numRawHires;
|
||||
std::cout << "{ " << rawTable[rawIdx][firstIdx] << ", "
|
||||
<< rawTable[rawIdx][secondIdx] << " }";
|
||||
if (sampleIdx < numSamples - 1)
|
||||
std::cout << ",\n";
|
||||
else
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::cout << "};\n";
|
||||
}
|
||||
|
||||
template <class Scalar>
|
||||
inline void testAll()
|
||||
{
|
||||
typedef Opm::Spe5FluidSystem<Scalar> FluidSystem;
|
||||
|
||||
enum {
|
||||
numPhases = FluidSystem::numPhases,
|
||||
waterPhaseIdx = FluidSystem::waterPhaseIdx,
|
||||
gasPhaseIdx = FluidSystem::gasPhaseIdx,
|
||||
oilPhaseIdx = FluidSystem::oilPhaseIdx,
|
||||
|
||||
numComponents = FluidSystem::numComponents,
|
||||
H2OIdx = FluidSystem::H2OIdx,
|
||||
C1Idx = FluidSystem::C1Idx,
|
||||
C3Idx = FluidSystem::C3Idx,
|
||||
C6Idx = FluidSystem::C6Idx,
|
||||
C10Idx = FluidSystem::C10Idx,
|
||||
C15Idx = FluidSystem::C15Idx,
|
||||
C20Idx = FluidSystem::C20Idx
|
||||
};
|
||||
|
||||
typedef Opm::NcpFlash<Scalar, FluidSystem> Flash;
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
typedef Opm::CompositionalFluidState<Scalar, FluidSystem> FluidState;
|
||||
|
||||
typedef Opm::ThreePhaseMaterialTraits<Scalar, waterPhaseIdx, oilPhaseIdx, gasPhaseIdx> MaterialTraits;
|
||||
typedef Opm::LinearMaterial<MaterialTraits> MaterialLaw;
|
||||
typedef typename MaterialLaw::Params MaterialLawParams;
|
||||
|
||||
typedef typename FluidSystem::template ParameterCache<Scalar> ParameterCache;
|
||||
|
||||
////////////
|
||||
// Initialize the fluid system and create the capillary pressure
|
||||
// parameters
|
||||
////////////
|
||||
Scalar T = 273.15 + 20; // 20 deg Celsius
|
||||
FluidSystem::init(/*minTemperature=*/T - 1,
|
||||
/*maxTemperature=*/T + 1,
|
||||
/*minPressure=*/1.0e4,
|
||||
/*maxTemperature=*/40.0e6);
|
||||
|
||||
// set the parameters for the capillary pressure law
|
||||
MaterialLawParams matParams;
|
||||
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
matParams.setPcMinSat(phaseIdx, 0.0);
|
||||
matParams.setPcMaxSat(phaseIdx, 0.0);
|
||||
}
|
||||
matParams.finalize();
|
||||
|
||||
////////////
|
||||
// Create a fluid state
|
||||
////////////
|
||||
FluidState gasFluidState;
|
||||
createSurfaceGasFluidSystem<FluidSystem>(gasFluidState);
|
||||
|
||||
FluidState fluidState;
|
||||
ParameterCache paramCache;
|
||||
|
||||
// temperature
|
||||
fluidState.setTemperature(T);
|
||||
|
||||
// oil pressure
|
||||
fluidState.setPressure(oilPhaseIdx, 4000 * 6894.7573); // 4000 PSI
|
||||
|
||||
// oil saturation
|
||||
fluidState.setSaturation(oilPhaseIdx, 1.0);
|
||||
fluidState.setSaturation(gasPhaseIdx, 1.0 - fluidState.saturation(oilPhaseIdx));
|
||||
|
||||
// oil composition: SPE-5 reservoir oil
|
||||
fluidState.setMoleFraction(oilPhaseIdx, H2OIdx, 0.0);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C1Idx, 0.50);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C3Idx, 0.03);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C6Idx, 0.07);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C10Idx, 0.20);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C15Idx, 0.15);
|
||||
fluidState.setMoleFraction(oilPhaseIdx, C20Idx, 0.05);
|
||||
|
||||
//makeOilSaturated<Scalar, FluidSystem>(fluidState, gasFluidState);
|
||||
|
||||
// set the saturations and pressures of the other phases
|
||||
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
|
||||
if (phaseIdx != oilPhaseIdx) {
|
||||
fluidState.setSaturation(phaseIdx, 0.0);
|
||||
fluidState.setPressure(phaseIdx, fluidState.pressure(oilPhaseIdx));
|
||||
}
|
||||
|
||||
// initial guess for the composition (needed by the ComputeFromReferencePhase
|
||||
// constraint solver. TODO: bug in ComputeFromReferencePhase?)
|
||||
guessInitial<FluidSystem>(fluidState, phaseIdx);
|
||||
}
|
||||
|
||||
typedef Opm::ComputeFromReferencePhase<Scalar, FluidSystem> CFRP;
|
||||
CFRP::solve(fluidState,
|
||||
paramCache,
|
||||
/*refPhaseIdx=*/oilPhaseIdx,
|
||||
/*setViscosity=*/false,
|
||||
/*setEnthalpy=*/false);
|
||||
|
||||
////////////
|
||||
// Calculate the total molarities of the components
|
||||
////////////
|
||||
ComponentVector totalMolarities;
|
||||
for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx)
|
||||
totalMolarities[compIdx] = fluidState.saturation(oilPhaseIdx)*fluidState.molarity(oilPhaseIdx, compIdx);
|
||||
|
||||
////////////
|
||||
// Gradually increase the volume for and calculate the gas
|
||||
// formation factor, oil formation volume factor and gas formation
|
||||
// volume factor.
|
||||
////////////
|
||||
|
||||
FluidState flashFluidState, surfaceFluidState;
|
||||
flashFluidState.assign(fluidState);
|
||||
//Flash::guessInitial(flashFluidState, totalMolarities);
|
||||
Flash::template solve<MaterialLaw>(flashFluidState, matParams, paramCache, totalMolarities);
|
||||
|
||||
Scalar surfaceAlpha = 1;
|
||||
surfaceAlpha = bringOilToSurface<Scalar, FluidSystem>(surfaceFluidState, surfaceAlpha, flashFluidState, /*guessInitial=*/true);
|
||||
Scalar rho_gRef = surfaceFluidState.density(gasPhaseIdx);
|
||||
Scalar rho_oRef = surfaceFluidState.density(oilPhaseIdx);
|
||||
|
||||
std::vector<std::array<Scalar, 10> > resultTable;
|
||||
|
||||
Scalar minAlpha = 0.98;
|
||||
Scalar maxAlpha = surfaceAlpha;
|
||||
|
||||
std::cout << "alpha[-] p[Pa] S_g[-] rho_o[kg/m^3] rho_g[kg/m^3] <M_o>[kg/mol] <M_g>[kg/mol] R_s[m^3/m^3] B_g[-] B_o[-]\n";
|
||||
int n = 300;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// ratio between the original and the current volume
|
||||
Scalar alpha = minAlpha + (maxAlpha - minAlpha)*i/(n - 1);
|
||||
|
||||
// increasing the volume means decreasing the molartity
|
||||
ComponentVector curTotalMolarities = totalMolarities;
|
||||
curTotalMolarities /= alpha;
|
||||
|
||||
// "flash" the modified reservoir oil
|
||||
Flash::template solve<MaterialLaw>(flashFluidState, matParams, paramCache, curTotalMolarities);
|
||||
|
||||
surfaceAlpha = bringOilToSurface<Scalar, FluidSystem>(surfaceFluidState,
|
||||
surfaceAlpha,
|
||||
flashFluidState,
|
||||
/*guessInitial=*/false);
|
||||
Scalar Rs =
|
||||
surfaceFluidState.saturation(gasPhaseIdx)
|
||||
/ surfaceFluidState.saturation(oilPhaseIdx);
|
||||
std::cout << alpha << " "
|
||||
<< flashFluidState.pressure(oilPhaseIdx) << " "
|
||||
<< flashFluidState.saturation(gasPhaseIdx) << " "
|
||||
<< flashFluidState.density(oilPhaseIdx) << " "
|
||||
<< flashFluidState.density(gasPhaseIdx) << " "
|
||||
<< flashFluidState.averageMolarMass(oilPhaseIdx) << " "
|
||||
<< flashFluidState.averageMolarMass(gasPhaseIdx) << " "
|
||||
<< Rs << " "
|
||||
<< rho_gRef/flashFluidState.density(gasPhaseIdx) << " "
|
||||
<< rho_oRef/flashFluidState.density(oilPhaseIdx) << " "
|
||||
<< "\n";
|
||||
|
||||
std::array<Scalar, 10> tmp;
|
||||
tmp[0] = alpha;
|
||||
tmp[1] = flashFluidState.pressure(oilPhaseIdx);
|
||||
tmp[2] = flashFluidState.saturation(gasPhaseIdx);
|
||||
tmp[3] = flashFluidState.density(oilPhaseIdx);
|
||||
tmp[4] = flashFluidState.density(gasPhaseIdx);
|
||||
tmp[5] = flashFluidState.averageMolarMass(oilPhaseIdx);
|
||||
tmp[6] = flashFluidState.averageMolarMass(gasPhaseIdx);
|
||||
tmp[7] = Rs;
|
||||
tmp[8] = rho_gRef/flashFluidState.density(gasPhaseIdx);
|
||||
tmp[9] = rho_oRef/flashFluidState.density(oilPhaseIdx);
|
||||
|
||||
resultTable.push_back(tmp);
|
||||
}
|
||||
|
||||
std::cout << "reference density oil [kg/m^3]: " << rho_oRef << "\n";
|
||||
std::cout << "reference density gas [kg/m^3]: " << rho_gRef << "\n";
|
||||
|
||||
Scalar hiresThresholdPressure = resultTable[20][1];
|
||||
printResult(resultTable,
|
||||
"Bg", /*firstIdx=*/1, /*secondIdx=*/8,
|
||||
/*hiresThreshold=*/hiresThresholdPressure);
|
||||
printResult(resultTable,
|
||||
"Bo", /*firstIdx=*/1, /*secondIdx=*/9,
|
||||
/*hiresThreshold=*/hiresThresholdPressure);
|
||||
printResult(resultTable,
|
||||
"Rs", /*firstIdx=*/1, /*secondIdx=*/7,
|
||||
/*hiresThreshold=*/hiresThresholdPressure);
|
||||
}
|
||||
|
||||
void testChiFlash()
|
||||
{
|
||||
using Scalar = double;
|
||||
typedef Opm::Spe5FluidSystem<Scalar> FluidSystem;
|
||||
using FluidSystem = Opm::TwoPhaseThreeComponentFluidSystem<Scalar>;
|
||||
|
||||
enum {
|
||||
numPhases = FluidSystem::numPhases,
|
||||
waterPhaseIdx = FluidSystem::waterPhaseIdx,
|
||||
gasPhaseIdx = FluidSystem::gasPhaseIdx,
|
||||
oilPhaseIdx = FluidSystem::oilPhaseIdx,
|
||||
|
||||
numComponents = FluidSystem::numComponents,
|
||||
H2OIdx = FluidSystem::H2OIdx,
|
||||
C1Idx = FluidSystem::C1Idx,
|
||||
C3Idx = FluidSystem::C3Idx,
|
||||
C6Idx = FluidSystem::C6Idx,
|
||||
C10Idx = FluidSystem::C10Idx,
|
||||
C15Idx = FluidSystem::C15Idx,
|
||||
C20Idx = FluidSystem::C20Idx
|
||||
};
|
||||
|
||||
//typedef Opm::NcpFlash<Scalar, FluidSystem> Flash;
|
||||
constexpr auto numComponents = FluidSystem::numComponents;
|
||||
typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
|
||||
typedef Opm::CompositionalFluidState<Scalar, FluidSystem> FluidState;
|
||||
|
||||
typedef Opm::ThreePhaseMaterialTraits<Scalar, waterPhaseIdx, oilPhaseIdx, gasPhaseIdx> MaterialTraits;
|
||||
typedef Opm::LinearMaterial<MaterialTraits> MaterialLaw;
|
||||
typedef typename MaterialLaw::Params MaterialLawParams;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user