Equilibration with water-gas ratio vs depth (RVWVD) table

This commit is contained in:
Paul Egberts 2022-08-26 16:44:19 +02:00
parent bae2c258a6
commit 1c70b5beea
5 changed files with 275 additions and 4 deletions

View File

@ -195,6 +195,42 @@ satRv(const double press, const double temp) const
}
template<class FluidSystem>
RvwVD<FluidSystem>::RvwVD(const int pvtRegionIdx,
const std::vector<double>& depth,
const std::vector<double>& rvw)
: pvtRegionIdx_(pvtRegionIdx)
, rvwVsDepth_(depth, rvw)
{
}
template<class FluidSystem>
double RvwVD<FluidSystem>::
operator()(const double depth,
const double press,
const double temp,
const double satWat) const
{
if (std::abs(satWat) > 1e-16) {
return satRvw(press, temp); //saturated Rvw
}
else {
if (rvwVsDepth_.xMin() > depth)
return rvwVsDepth_.valueAt(0);
else if (rvwVsDepth_.xMax() < depth)
return rvwVsDepth_.valueAt(rvwVsDepth_.numSamples() - 1);
return std::min(satRvw(press, temp), rvwVsDepth_.eval(depth, /*extrapolate=*/false));
}
}
template<class FluidSystem>
double RvwVD<FluidSystem>::
satRvw(const double press, const double temp) const
{
return FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_, temp, press);
}
template<class FluidSystem>
RsSatAtContact<FluidSystem>::
RsSatAtContact(const int pvtRegionIdx, const double pContact, const double T_contact)
@ -255,16 +291,48 @@ satRv(const double press, const double temp) const
return FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, temp, press);;
}
template<class FluidSystem>
RvwSatAtContact<FluidSystem>::
RvwSatAtContact(const int pvtRegionIdx, const double pContact, const double T_contact)
: pvtRegionIdx_(pvtRegionIdx)
{
rvwSatContact_ = satRvw(pContact, T_contact);
}
template<class FluidSystem>
double RvwSatAtContact<FluidSystem>::
operator()(const double /*depth*/,
const double press,
const double temp,
const double satWat) const
{
if (satWat > 0.0) {
return satRvw(press, temp);
}
else {
return std::min(satRvw(press, temp), rvwSatContact_);
}
}
template<class FluidSystem>
double RvwSatAtContact<FluidSystem>::
satRvw(const double press, const double temp) const
{
return FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_, temp, press);;
}
} // namespace Miscibility
EquilReg::EquilReg(const EquilRecord& rec,
std::shared_ptr<Miscibility::RsFunction> rs,
std::shared_ptr<Miscibility::RsFunction> rv,
std::shared_ptr<Miscibility::RsFunction> rvw,
const TabulatedFunction& saltVdTable,
const int pvtIdx)
: rec_ (rec)
, rs_ (rs)
, rv_ (rv)
, rvw_ (rvw)
, saltVdTable_ (saltVdTable)
, pvtIdx_ (pvtIdx)
{
@ -317,6 +385,12 @@ EquilReg::evaporationCalculator() const
return *this->rv_;
}
const EquilReg::CalcWaterEvaporation&
EquilReg::waterEvaporationCalculator() const
{
return *this->rvw_;
}
const EquilReg::TabulatedFunction&
EquilReg::saltVdTable() const
{
@ -556,7 +630,9 @@ namespace Miscibility {
template class RsVD<FS>;
template class RsSatAtContact<FS>;
template class RvSatAtContact<FS>;
template class RvwSatAtContact<FS>;
template class RvVD<FS>;
template class RvwVD<FS>;
}
} // namespace Equil

View File

@ -363,6 +363,56 @@ private:
};
/**
* Type that implements "vaporized water-gas ratio"
* tabulated as a function of depth policy. Data
* typically taken from keyword 'RVWVD'.
*/
template <class FluidSystem>
class RvwVD : public RsFunction
{
public:
/**
* Constructor.
*
* \param[in] pvtRegionIdx The pvt region index
* \param[in] depth Depth nodes.
* \param[in] rvw Evaporized water-gasl ratio at @c depth.
*/
RvwVD(const int pvtRegionIdx,
const std::vector<double>& depth,
const std::vector<double>& rvw);
/**
* Function call.
*
* \param[in] depth Depth at which to calculate RVW
* value.
*
* \param[in] press Pressure at which to calculate RVW
* value.
*
* \param[in] temp Temperature at which to calculate RVW
* value.
*
* \return Vaporized water-gas ratio (RVW) at depth @c
* depth and pressure @c press.
*/
double operator()(const double depth,
const double press,
const double temp,
const double satWat = 0.0) const;
private:
using RvwVsDepthFunc = Tabulated1DFunction<double>;
const int pvtRegionIdx_;
RvwVsDepthFunc rvwVsDepth_;
double satRvw(const double press, const double temp) const;
};
/**
* Class that implements "dissolved gas-oil ratio" (Rs)
* as function of depth and pressure as follows:
@ -472,6 +522,61 @@ private:
double satRv(const double press, const double temp) const;
};
//TODO: check if needed
/**
* Class that implements "vaporized water-gas ratio" (Rvw)
* as function of depth and pressure as follows:
*
* 1. The Rvw at the gas-water contact is equal to the
* saturated Rv value, RvwSatContact.
*
* 2. The Rvw elsewhere is equal to RvwSatContact, but
* constrained to the saturated value as given by the
* local pressure.
*
* This should yield Rvw-values that are constant below the
* contact, and decreasing above the contact.
*/
template <class FluidSystem>
class RvwSatAtContact : public RsFunction
{
public:
/**
* Constructor.
*
* \param[in] pvtRegionIdx The pvt region index
* \param[in] pContact oil pressure at the contact
* \param[in] T_contact temperature at the contact
*/
RvwSatAtContact(const int pvtRegionIdx, const double pContact, const double T_contact);
/**
* Function call.
*
* \param[in] depth Depth at which to calculate RVW
* value.
*
* \param[in] press Pressure at which to calculate RVW
* value.
*
* \param[in] temp Temperature at which to calculate RVW
* value.
*
* \return Dissolved water-gas ratio (RVW) at depth @c
* depth and pressure @c press.
*/
double operator()(const double /*depth*/,
const double press,
const double temp,
const double satWat = 0.0) const;
private:
const int pvtRegionIdx_;
double rvwSatContact_;
double satRvw(const double press, const double temp) const;
};
} // namespace Miscibility
/**
@ -504,11 +609,13 @@ public:
* \param[in] rec Equilibration data of current region.
* \param[in] rs Calculator of dissolved gas-oil ratio.
* \param[in] rv Calculator of vapourised oil-gas ratio.
* \param[in] rvw Calculator of vapourised water-gas ratio.
* \param[in] pvtRegionIdx The pvt region index
*/
EquilReg(const EquilRecord& rec,
std::shared_ptr<Miscibility::RsFunction> rs,
std::shared_ptr<Miscibility::RsFunction> rv,
std::shared_ptr<Miscibility::RsFunction> rvw,
const TabulatedFunction& saltVdTable,
const int pvtIdx);
@ -522,6 +629,12 @@ public:
*/
using CalcEvaporation = Miscibility::RsFunction;
/**
* Type of vapourised water-gas ratio calculator.
*/
using CalcWaterEvaporation = Miscibility::RsFunction;
/**
* Datum depth in current region
*/
@ -577,6 +690,12 @@ public:
*/
const CalcEvaporation& evaporationCalculator() const;
/**
* Retrieve vapourised water-gas ratio calculator of current
* region.
*/
const CalcWaterEvaporation& waterEvaporationCalculator() const;
const TabulatedFunction& saltVdTable() const;
/**
* Retrieve pvtIdx of the region.
@ -587,6 +706,7 @@ private:
EquilRecord rec_; /**< Equilibration data */
std::shared_ptr<Miscibility::RsFunction> rs_; /**< RS calculator */
std::shared_ptr<Miscibility::RsFunction> rv_; /**< RV calculator */
std::shared_ptr<Miscibility::RsFunction> rvw_; /**< RVW calculator */
const TabulatedFunction& saltVdTable_;
const int pvtIdx_;
};

View File

@ -34,6 +34,7 @@
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Tables/RsvdTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/RvvdTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/RvwvdTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/PbvdTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/PdvdTable.hpp>
#include <opm/input/eclipse/EclipseState/Tables/SaltvdTable.hpp>
@ -324,6 +325,7 @@ density(const double depth,
return rho;
}
// TODO: add RVW
template<class FluidSystem, class RV>
Gas<FluidSystem,RV>::
Gas(const double temp,
@ -1203,6 +1205,7 @@ InitialStateComputer(MaterialLawManager& materialLawManager,
std::vector<double>(grid.size(/*codim=*/0))),
rs_(grid.size(/*codim=*/0)),
rv_(grid.size(/*codim=*/0)),
rvw_(grid.size(/*codim=*/0)),
cartesianIndexMapper_(cartMapper)
{
//Check for presence of kw SWATINIT
@ -1322,6 +1325,54 @@ InitialStateComputer(MaterialLawManager& materialLawManager,
}
}
rvwFunc_.reserve(rec.size());
if (FluidSystem::enableVaporizedWater()) {
for (size_t i = 0; i < rec.size(); ++i) {
if (eqlmap.cells(i).empty()) {
rvwFunc_.push_back(std::shared_ptr<Miscibility::RvwVD<FluidSystem>>());
continue;
}
const int pvtIdx = regionPvtIdx_[i];
if (!rec[i].wetGasInitConstantRv()) {
const TableContainer& rvwvdTables = tables.getRvwvdTables();
//const TableContainer& pdvdTables = tables.getPdvdTables();
if (rvwvdTables.size() > 0) {
const RvwvdTable& rvwvdTable = rvwvdTables.getTable<RvwvdTable>(i);
std::vector<double> depthColumn = rvwvdTable.getColumn("DEPTH").vectorCopy();
std::vector<double> rvwvdColumn = rvwvdTable.getColumn("RVWVD").vectorCopy();
rvwFunc_.push_back(std::make_shared<Miscibility::RvwVD<FluidSystem>>(pvtIdx,
depthColumn, rvwvdColumn));
// } else if (pdvdTables.size() > 0) {
// const PdvdTable& pdvdTable = pdvdTables.getTable<PdvdTable>(i);
// std::vector<double> depthColumn = pdvdTable.getColumn("DEPTH").vectorCopy();
// std::vector<double> pdewColumn = pdvdTable.getColumn("PDEW").vectorCopy();
// rvFunc_.push_back(std::make_shared<Miscibility::PDVD<FluidSystem>>(pvtIdx,
// depthColumn, pdewColumn));
} else {
throw std::runtime_error("Cannot initialise: RVWVD table not available.");
}
}
// else {
// if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
// throw std::runtime_error(
// "Cannot initialise: when no explicit RVVD table is given, \n"
// "datum depth must be at the gas-oil-contact. "
// "In EQUIL region "+std::to_string(i + 1)+" (counting from 1), this does not hold.");
// }
// const double pContact = rec[i].datumDepthPressure() + rec[i].gasOilContactCapillaryPressure();
// const double TContact = 273.15 + 20; // standard temperature for now
// rvFunc_.push_back(std::make_shared<Miscibility::RvSatAtContact<FluidSystem>>(pvtIdx,pContact, TContact));
// }
}
}
else {
for (size_t i = 0; i < rec.size(); ++i) {
rvwFunc_.push_back(std::make_shared<Miscibility::NoMixing>());
}
}
// EXTRACT the initial temperature
updateInitialTemperature_(eclipseState);
@ -1603,7 +1654,7 @@ calcPressSatRsRv(const RMap& reg,
}
const auto eqreg = EquilReg {
rec[r], this->rsFunc_[r], this->rvFunc_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
};
// Ensure gas/oil and oil/water contacts are within the span for the
@ -1664,9 +1715,10 @@ cellLoop(const CellRange& cells,
auto saturations = Details::PhaseQuantityValue{};
auto Rs = 0.0;
auto Rv = 0.0;
auto Rvw = 0.0;
for (const auto& cell : cells) {
eqmethod(cell, pressures, saturations, Rs, Rv);
eqmethod(cell, pressures, saturations, Rs, Rv, Rvw);
if (oilActive) {
this->pp_ [oilPos][cell] = pressures.oil;
@ -1687,6 +1739,10 @@ cellLoop(const CellRange& cells,
this->rs_[cell] = Rs;
this->rv_[cell] = Rv;
}
if (watActive && gasActive) {
this->rvw_[cell] = Rvw;
}
}
}
@ -1714,7 +1770,8 @@ equilibrateCellCentres(const CellRange& cells,
Details::PhaseQuantityValue& pressures,
Details::PhaseQuantityValue& saturations,
double& Rs,
double& Rv) -> void
double& Rv,
double& Rvw) -> void
{
const auto pos = CellPos {
cell, cellCenterDepth_[cell]
@ -1730,6 +1787,9 @@ equilibrateCellCentres(const CellRange& cells,
Rv = eqreg.evaporationCalculator()
(pos.depth, pressures.gas, temp, saturations.oil);
Rvw = eqreg.waterEvaporationCalculator()
(pos.depth, pressures.gas, temp, saturations.water);
});
}
@ -1759,7 +1819,8 @@ equilibrateHorizontal(const CellRange& cells,
Details::PhaseQuantityValue& pressures,
Details::PhaseQuantityValue& saturations,
double& Rs,
double& Rv) -> void
double& Rv,
double& Rvw) -> void
{
pressures .reset();
saturations.reset();
@ -1785,6 +1846,9 @@ equilibrateHorizontal(const CellRange& cells,
Rv = eqreg.evaporationCalculator()
(cz, pressures.gas, temp, saturations.oil);
Rvw = eqreg.waterEvaporationCalculator()
(cz, pressures.gas, temp, saturations.water);
});
}

View File

@ -128,6 +128,7 @@ private:
const double press) const;
};
//TODO:add argument rvw
template <class FluidSystem, class RV>
class Gas
{
@ -741,6 +742,7 @@ private:
std::vector< std::shared_ptr<Miscibility::RsFunction> > rsFunc_;
std::vector< std::shared_ptr<Miscibility::RsFunction> > rvFunc_;
std::vector< std::shared_ptr<Miscibility::RsFunction> > rvwFunc_;
using TabulatedFunction = Tabulated1DFunction<double>;
std::vector<TabulatedFunction> saltVdTable_;
std::vector<TabulatedFunction> saltpVdTable_;

View File

@ -264,6 +264,7 @@ BOOST_AUTO_TEST_CASE(PhasePressure)
record,
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0
};
@ -320,24 +321,28 @@ BOOST_AUTO_TEST_CASE(CellSubset)
Opm::EQUIL::EquilReg(record[0],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[0],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[1],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[1],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
};
@ -423,24 +428,28 @@ BOOST_AUTO_TEST_CASE(RegMapping)
Opm::EQUIL::EquilReg(record[0],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[0],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[1],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
,
Opm::EQUIL::EquilReg(record[1],
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
std::make_shared<Opm::EQUIL::Miscibility::NoMixing>(),
trivialSaltVdTable,
0)
};