Basic Equilibration: Prepare for Subdivision Strategy

This commit is the first step of several that implements ECLIPSE's
"accurate fluid-in-place" model initialization procedure based on
subdividing the vertical range/extent of individual cells.  This
first step puts the O/G/W phase-pressure calculation into a helper
class,

    Opm::EQUIL::Details::PressureTable<>

through which phase pressure values can be calculated at abritrary
depths rather than just at the cell centre depths.  In other words,
this helper class extends and subsumes the responsibilities of the
existing helper functions

    Opm::EQUIL::Details::PhasePressure::assign()
    Opm::EQUIL::Details::PhasePressure::oil()
    Opm::EQUIL::Details::PhasePressure::gas()
    Opm::EQUIL::Details::PhasePressure::water()

We still use the same ODE-based evaluation procedure for the phase
pressures and the equilibrateOWG() helper function still computes
the phase pressure values at cell centre depths only.

That, in turn, corresponds to the "N = 0" case (steady state) of the
basic equilibration facility.
This commit is contained in:
Bård Skaflestad 2020-04-06 17:02:47 +02:00
parent 11b0a409d1
commit d039a1d60e

View File

@ -53,8 +53,12 @@
#include <opm/material/fluidstates/SimpleModularFluidState.hpp> #include <opm/material/fluidstates/SimpleModularFluidState.hpp>
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp> #include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
#include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <cstddef>
#include <limits>
#include <stdexcept>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -278,191 +282,484 @@ private:
}; };
} // namespace PhasePressODE } // namespace PhasePressODE
template <class FluidSystem, class Region>
namespace PhasePressure { class PressureTable
template <class Grid,
class PressFunction,
class CellRange>
void assign(const Grid& grid,
const std::array<PressFunction, 2>& f ,
const double split,
const CellRange& cells,
std::vector<double>& p)
{ {
public:
using VSpan = std::array<double, 2>;
enum { up = 0, down = 1 }; /// Constructor
///
/// \param[in] gravity Norm of gravity vector (acceleration strength due
/// to gravity). Normally the standardised value at Tellus equator
/// (9.80665 m/s^2).
///
/// \param[in] samplePoints Number of equally spaced depth sample points
/// in each internal phase pressure table.
explicit PressureTable(const double gravity,
const int samplePoints = 2000)
: gravity_(gravity)
, nsample_(samplePoints)
{}
std::vector<double>::size_type c = 0; /// Copy constructor
for (typename CellRange::const_iterator ///
ci = cells.begin(), ce = cells.end(); /// \param[in] rhs Source object for copy initialization.
ci != ce; ++ci, ++c) PressureTable(const PressureTable& rhs)
: gravity_(rhs.gravity)
, nsample_(rhs.nsample_)
{ {
assert (c < p.size()); this->copyInPointers(rhs);
const double z = Opm::UgGridHelpers::cellCenterDepth(grid, *ci);
p[c] = (z < split) ? f[up](z) : f[down](z);
} }
}
template <class FluidSystem, /// Move constructor
class Grid, ///
class Region, /// \param[in,out] rhs Source object for move initialization. On output,
class CellRange> /// left in a moved-from ("valid but unspecified") state. Internal
void water(const Grid& grid, /// pointers in \p rhs are null (\c unique_ptr guarantee).
const Region& reg, PressureTable(PressureTable&& rhs)
const std::array<double,2>& span , : gravity_(rhs.gravity_)
const double grav, , nsample_(rhs.nsample_)
double& poWoc, , oil_ (std::move(rhs.oil_))
const CellRange& cells, , gas_ (std::move(rhs.gas_))
std::vector<double>& press) , wat_ (std::move(rhs.wat_))
{ {}
using PhasePressODE::Water;
typedef Water<FluidSystem> ODE;
const double T = 273.15 + 20; // standard temperature for now /// Assignment operator
ODE drho(T, reg.pvtIdx() , grav); ///
/// \param[in] rhs Source object.
///
/// \return \code *this \endcode.
PressureTable& operator=(const PressureTable& rhs)
{
this->gravity_ = rhs.gravity_;
this->nsample_ = rhs.nsample_;
this->copyInPointers(rhs);
double z0; return *this;
double p0; }
if (reg.datum() > reg.zwoc()) {//Datum in water zone
z0 = reg.datum(); /// Move-assignment operator
p0 = reg.pressure(); ///
/// \param[in] rhs Source object. On output, left in a moved-from ("valid
/// but unspecified") state. Internal pointers in \p rhs are null (\c
/// unique_ptr guarantee).
///
/// \return \code *this \endcode.
PressureTable& operator=(PressureTable&& rhs)
{
this->gravity_ = rhs.gravity_;
this->nsample_ = rhs.nsample_;
this->oil_ = std::move(rhs.oil_);
this->gas_ = std::move(rhs.gas_);
this->wat_ = std::move(rhs.wat_);
return *this;
}
void equilibrate(const Region& reg,
const VSpan& span)
{
// One of the PressureTable::equil_*() member functions.
auto equil = this->selectEquilibrationStrategy(reg);
(this->*equil)(reg, span);
}
/// Predicate for whether or not oil is an active phase
bool oilActive() const
{
return FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
}
/// Predicate for whether or not gas is an active phase
bool gasActive() const
{
return FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx);
}
/// Predicate for whether or not water is an active phase
bool waterActive() const
{
return FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
}
/// Evaluate oil phase pressure at specified depth.
///
/// \param[in] depth Depth of evaluation point. Should generally be
/// within the \c span from the previous call to \code equilibrate()
/// \endcode.
///
/// \return Oil phase pressure at specified depth.
double oil(const double depth) const
{
this->checkPtr(this->oil_.get(), "OIL");
return this->oil_->value(depth);
}
/// Evaluate gas phase pressure at specified depth.
///
/// \param[in] depth Depth of evaluation point. Should generally be
/// within the \c span from the previous call to \code equilibrate()
/// \endcode.
///
/// \return Gas phase pressure at specified depth.
double gas(const double depth) const
{
this->checkPtr(this->gas_.get(), "GAS");
return this->gas_->value(depth);
}
/// Evaluate water phase pressure at specified depth.
///
/// \param[in] depth Depth of evaluation point. Should generally be
/// within the \c span from the previous call to \code equilibrate()
/// \endcode.
///
/// \return Water phase pressure at specified depth.
double water(const double depth) const
{
this->checkPtr(this->wat_.get(), "WATER");
return this->wat_->value(depth);
}
private:
template <class ODE>
class PressureFunction
{
public:
struct InitCond {
double depth;
double pressure;
};
explicit PressureFunction(const ODE& ode,
const InitCond& ic,
const int nsample,
const VSpan& span)
: initial_(ic)
{
this->value_[Direction::Up] = std::make_unique<Distribution>
(ode, VSpan {{ ic.depth, span[0] }}, ic.pressure, nsample);
this->value_[Direction::Down] = std::make_unique<Distribution>
(ode, VSpan {{ ic.depth, span[1] }}, ic.pressure, nsample);
}
PressureFunction(const PressureFunction& rhs)
: initial_(rhs.initial_)
{
this->value_[Direction::Up] =
std::make_unique<Distribution>(*rhs.value_[Direction::Up]);
this->value_[Direction::Down] =
std::make_unique<Distribution>(*rhs.value_[Direction::Down]);
}
PressureFunction(PressureFunction&& rhs) = default;
PressureFunction& operator=(const PressureFunction& rhs)
{
this->initial_ = rhs.initial_;
this->value_[Direction::Up] =
std::make_unique<Distribution>(*rhs.value_[Direction::Up]);
this->value_[Direction::Down] =
std::make_unique<Distribution>(*rhs.value_[Direction::Down]);
return *this;
}
PressureFunction& operator=(PressureFunction&& rhs)
{
this->initial_ = rhs.initial_;
this->value_ = std::move(rhs.value_);
return *this;
}
double value(const double depth) const
{
if (depth < this->initial_.depth) {
// Value above initial condition depth.
return (*this->value_[Direction::Up])(depth);
}
else if (depth > this->initial_.depth) {
// Value below initial condition depth.
return (*this->value_[Direction::Down])(depth);
} }
else { else {
z0 = reg.zwoc(); // Value *at* initial condition depth.
p0 = poWoc - reg.pcowWoc(); // Water pressure at contact return this->initial_.pressure;
}
} }
std::array<double,2> up = {{ z0, span[0] }}; private:
std::array<double,2> down = {{ z0, span[1] }}; enum Direction : std::size_t { Up, Down, NumDir };
typedef Details::RK4IVP<ODE> WPress; using Distribution = Details::RK4IVP<ODE>;
std::array<WPress,2> wpress = { using DistrPtr = std::unique_ptr<Distribution>;
{
WPress(drho, up , p0, 2000) InitCond initial_;
, std::array<DistrPtr, Direction::NumDir> value_;
WPress(drho, down, p0, 2000)
}
}; };
assign(grid, wpress, z0, cells, press); using OilPressODE = PhasePressODE::Oil<
FluidSystem, typename Region::CalcDissolution
>;
if (reg.datum() > reg.zwoc()) { using GasPressODE = PhasePressODE::Gas<
// Return oil pressure at contact FluidSystem, typename Region::CalcEvaporation
poWoc = wpress[0](reg.zwoc()) + reg.pcowWoc(); >;
using WatPressODE = PhasePressODE::Water<FluidSystem>;
using OPress = PressureFunction<OilPressODE>;
using GPress = PressureFunction<GasPressODE>;
using WPress = PressureFunction<WatPressODE>;
using Strategy = void (PressureTable::*)
(const Region&, const VSpan&);
double gravity_;
int nsample_;
double temperature_{ 273.15 + 20 };
std::unique_ptr<OPress> oil_{};
std::unique_ptr<GPress> gas_{};
std::unique_ptr<WPress> wat_{};
template <typename PressFunc>
void checkPtr(const PressFunc* phasePress,
const std::string& phaseName) const
{
if (phasePress != nullptr) { return; }
throw std::invalid_argument {
"Phase pressure function for \"" + phaseName
+ "\" most not be null"
};
} }
}
template <class FluidSystem, Strategy selectEquilibrationStrategy(const Region& reg) const
class Grid, {
class Region, if (reg.datum() > reg.zwoc()) { // Datum in water zone
class CellRange> return &PressureTable::equil_WOG;
void oil(const Grid& grid, }
else if (reg.datum() < reg.zgoc()) { // Datum in gas zone
return &PressureTable::equil_GOW;
}
else { // Datum in oil zone
return &PressureTable::equil_OWG;
}
}
void copyInPointers(const PressureTable& rhs)
{
if (rhs.oil_ != nullptr) {
this->oil_ = std::make_unique<OPress>(*rhs.oil_);
}
if (rhs.gas_ != nullptr) {
this->gas_ = std::make_unique<GPress>(*rhs.gas_);
}
if (rhs.wat_ != nullptr) {
this->wat_ = std::make_unique<WPress>(*rhs.wat_);
}
}
void equil_WOG(const Region& reg, const VSpan& span);
void equil_GOW(const Region& reg, const VSpan& span);
void equil_OWG(const Region& reg, const VSpan& span);
void makeOilPressure(const typename OPress::InitCond& ic,
const Region& reg, const Region& reg,
const std::array<double,2>& span , const VSpan& span);
const double grav,
const CellRange& cells,
std::vector<double>& press,
double& poWoc,
double& poGoc)
{
using PhasePressODE::Oil;
typedef Oil<FluidSystem, typename Region::CalcDissolution> ODE;
const double T = 273.15 + 20; // standard temperature for now void makeGasPressure(const typename GPress::InitCond& ic,
ODE drho(T, reg.dissolutionCalculator(),
reg.pvtIdx(), grav);
double z0;
double p0;
if (reg.datum() > reg.zwoc()) {//Datum in water zone, poWoc given
z0 = reg.zwoc();
p0 = poWoc;
}
else if (reg.datum() < reg.zgoc()) {//Datum in gas zone, poGoc given
z0 = reg.zgoc();
p0 = poGoc;
}
else { //Datum in oil zone
z0 = reg.datum();
p0 = reg.pressure();
}
std::array<double,2> up = {{ z0, span[0] }};
std::array<double,2> down = {{ z0, span[1] }};
typedef Details::RK4IVP<ODE> OPress;
std::array<OPress,2> opress = {
{
OPress(drho, up , p0, 2000)
,
OPress(drho, down, p0, 2000)
}
};
assign(grid, opress, z0, cells, press);
const double woc = reg.zwoc();
if (z0 > woc) { poWoc = opress[0](woc); } // WOC above datum
else if (z0 < woc) { poWoc = opress[1](woc); } // WOC below datum
else { poWoc = p0; } // WOC *at* datum
const double goc = reg.zgoc();
if (z0 > goc) { poGoc = opress[0](goc); } // GOC above datum
else if (z0 < goc) { poGoc = opress[1](goc); } // GOC below datum
else { poGoc = p0; } // GOC *at* datum
}
template <class FluidSystem,
class Grid,
class Region,
class CellRange>
void gas(const Grid& grid,
const Region& reg, const Region& reg,
const std::array<double,2>& span , const VSpan& span);
const double grav,
double& poGoc, void makeWatPressure(const typename WPress::InitCond& ic,
const CellRange& cells, const Region& reg,
std::vector<double>& press) const VSpan& span);
};
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
equil_WOG(const Region& reg, const VSpan& span)
{ {
using PhasePressODE::Gas; // Datum depth in water zone. Calculate phase pressure for water first,
typedef Gas<FluidSystem, typename Region::CalcEvaporation> ODE; // followed by oil and gas if applicable.
const double T = 273.15 + 20; // standard temperature for now if (! this->waterActive()) {
ODE drho(T, reg.evaporationCalculator(), throw std::invalid_argument {
reg.pvtIdx(), grav); "Don't know how to interpret EQUIL datum depth in "
"WATER zone in model without active water phase"
double z0; };
double p0;
if (reg.datum() < reg.zgoc()) {//Datum in gas zone
z0 = reg.datum();
p0 = reg.pressure();
}
else {
z0 = reg.zgoc();
p0 = poGoc + reg.pcgoGoc(); // Gas pressure at contact
} }
std::array<double,2> up = {{ z0, span[0] }};
std::array<double,2> down = {{ z0, span[1] }};
typedef Details::RK4IVP<ODE> GPress;
std::array<GPress,2> gpress = {
{ {
GPress(drho, up , p0, 2000) const auto ic = typename WPress::InitCond {
, reg.datum(), reg.pressure()
GPress(drho, down, p0, 2000)
}
}; };
assign(grid, gpress, z0, cells, press); this->makeWatPressure(ic, reg, span);
}
if (reg.datum() < reg.zgoc()) { if (this->oilActive()) {
// Return oil pressure at contact // Pcow = Po - Pw => Po = Pw + Pcow
poGoc = gpress[1](reg.zgoc()) - reg.pcgoGoc(); const auto ic = typename OPress::InitCond {
reg.zwoc(),
this->water(reg.zwoc()) + reg.pcowWoc()
};
this->makeOilPressure(ic, reg, span);
}
if (this->gasActive()) {
// Pcgo = Pg - Po => Pg = Po + Pcgo
const auto ic = typename GPress::InitCond {
reg.zgoc(),
this->oil(reg.zgoc()) + reg.pcgoGoc()
};
this->makeGasPressure(ic, reg, span);
} }
} }
} // namespace PhasePressure
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
equil_GOW(const Region& reg, const VSpan& span)
{
// Datum depth in gas zone. Calculate phase pressure for gas first,
// followed by oil and water if applicable.
if (! this->gasActive()) {
throw std::invalid_argument {
"Don't know how to interpret EQUIL datum depth in "
"GAS zone in model without active gas phase"
};
}
{
const auto ic = typename GPress::InitCond {
reg.datum(), reg.pressure()
};
this->makeGasPressure(ic, reg, span);
}
if (this->oilActive()) {
// Pcgo = Pg - Po => Po = Pg - Pcgo
const auto ic = typename OPress::InitCond {
reg.zgoc(),
this->gas(reg.zgoc()) - reg.pcgoGoc()
};
this->makeOilPressure(ic, reg, span);
}
if (this->waterActive()) {
// Pcow = Po - Pw => Pw = Po - Pcow
const auto ic = typename WPress::InitCond {
reg.zwoc(),
this->oil(reg.zwoc()) - reg.pcowWoc()
};
this->makeWatPressure(ic, reg, span);
}
}
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
equil_OWG(const Region& reg, const VSpan& span)
{
// Datum depth in gas zone. Calculate phase pressure for gas first,
// followed by oil and water if applicable.
if (! this->oilActive()) {
throw std::invalid_argument {
"Don't know how to interpret EQUIL datum depth in "
"OIL zone in model without active oil phase"
};
}
{
const auto ic = typename OPress::InitCond {
reg.datum(), reg.pressure()
};
this->makeOilPressure(ic, reg, span);
}
if (this->waterActive()) {
// Pcow = Po - Pw => Pw = Po - Pcow
const auto ic = typename WPress::InitCond {
reg.zwoc(),
this->oil(reg.zwoc()) - reg.pcowWoc()
};
this->makeWatPressure(ic, reg, span);
}
if (this->gasActive()) {
// Pcgo = Pg - Po => Pg = Po + Pcgo
const auto ic = typename GPress::InitCond {
reg.zgoc(),
this->oil(reg.zgoc()) + reg.pcgoGoc()
};
this->makeGasPressure(ic, reg, span);
}
}
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
makeOilPressure(const typename OPress::InitCond& ic,
const Region& reg,
const VSpan& span)
{
const auto drho = OilPressODE {
this->temperature_, reg.dissolutionCalculator(),
reg.pvtIdx(), this->gravity_
};
this->oil_ = std::make_unique<OPress>(drho, ic, this->nsample_, span);
}
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
makeGasPressure(const typename GPress::InitCond& ic,
const Region& reg,
const VSpan& span)
{
const auto drho = GasPressODE {
this->temperature_, reg.evaporationCalculator(),
reg.pvtIdx(), this->gravity_
};
this->gas_ = std::make_unique<GPress>(drho, ic, this->nsample_, span);
}
template <class FluidSystem, class Region>
void PressureTable<FluidSystem, Region>::
makeWatPressure(const typename WPress::InitCond& ic,
const Region& reg,
const VSpan& span)
{
const auto drho = WatPressODE {
this->temperature_, reg.pvtIdx(), this->gravity_
};
this->wat_ = std::make_unique<WPress>(drho, ic, this->nsample_, span);
}
template <class FluidSystem, template <class FluidSystem,
class Grid, class Grid,
@ -475,71 +772,80 @@ void equilibrateOWG(const Grid& grid,
const CellRange& cells, const CellRange& cells,
std::vector< std::vector<double> >& press) std::vector< std::vector<double> >& press)
{ {
const bool water = FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx); using PhaseIX = std::vector<std::vector<double>>::size_type;
const bool oil = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx); auto ptable = PressureTable<FluidSystem, Region>{ grav };
const bool gas = FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx);
const int oilpos = FluidSystem::oilPhaseIdx;
const int waterpos = FluidSystem::waterPhaseIdx;
const int gaspos = FluidSystem::gasPhaseIdx;
if (reg.datum() > reg.zwoc()) { // Datum in water zone ptable.equilibrate(reg, span);
double poWoc = -1;
double poGoc = -1;
if (water) { const auto oilpos = static_cast<PhaseIX>(FluidSystem::oilPhaseIdx);
PhasePressure::water<FluidSystem>(grid, reg, span, grav, poWoc, const auto gaspos = static_cast<PhaseIX>(FluidSystem::gasPhaseIdx);
cells, press[waterpos]); const auto waterpos = static_cast<PhaseIX>(FluidSystem::waterPhaseIdx);
}
if (oil) { auto ix = std::vector<double>::size_type{0};
PhasePressure::oil<FluidSystem>(grid, reg, span, grav, cells, for (const auto& cell : cells) {
press[oilpos], poWoc, poGoc); const auto depth = Opm::UgGridHelpers::cellCenterDepth(grid, cell);
}
if (gas) { if (ptable.oilActive()) { press[oilpos] [ix] = ptable.oil (depth); }
PhasePressure::gas<FluidSystem>(grid, reg, span, grav, poGoc, if (ptable.gasActive()) { press[gaspos] [ix] = ptable.gas (depth); }
cells, press[gaspos]); if (ptable.waterActive()) { press[waterpos][ix] = ptable.water(depth); }
}
}
else if (reg.datum() < reg.zgoc()) { // Datum in gas zone
double poWoc = -1;
double poGoc = -1;
if (gas) { ++ix;
PhasePressure::gas<FluidSystem>(grid, reg, span, grav, poGoc,
cells, press[gaspos]);
} }
}
if (oil) { template <typename Grid, typename CellRange>
PhasePressure::oil<FluidSystem>(grid, reg, span, grav, cells, void verticalExtent(const Grid& grid,
press[oilpos], poWoc, poGoc); const CellRange& cells,
} int& cellcount,
std::array<double,2>& span)
{
// This code is only supported in three space dimensions
assert (Grid::dimensionworld == 3);
if (water) { span[0] = std::numeric_limits<double>::max();
PhasePressure::water<FluidSystem>(grid, reg, span, grav, poWoc, span[1] = std::numeric_limits<double>::lowest();
cells, press[waterpos]); cellcount = 0;
}
}
else { // Datum in oil zone
double poWoc = -1;
double poGoc = -1;
if (oil) { const int nd = Grid::dimensionworld;
PhasePressure::oil<FluidSystem>(grid, reg, span, grav, cells,
press[oilpos], poWoc, poGoc);
}
if (water) { // Define vertical span as
PhasePressure::water<FluidSystem>(grid, reg, span, grav, poWoc, //
cells, press[waterpos]); // [minimum(node depth(cells)), maximum(node depth(cells))]
} //
// Note: We use a sledgehammer approach--looping all
// the nodes of all the faces of all the 'cells'--to
// compute those bounds. This necessarily entails
// visiting some nodes (and faces) multiple times.
//
// Note: The implementation of 'RK4IVP<>' implicitly
// imposes the requirement that cell centroids are all
// within this vertical span. That requirement is not
// checked.
auto cell2Faces = Opm::UgGridHelpers::cell2Faces(grid);
auto faceVertices = Opm::UgGridHelpers::face2Vertices(grid);
if (gas) { for (typename CellRange::const_iterator
PhasePressure::gas<FluidSystem>(grid, reg, span, grav, poGoc, ci = cells.begin(), ce = cells.end();
cells, press[gaspos]); ci != ce; ++ci, ++cellcount)
{
for (auto fi = cell2Faces[*ci].begin(),
fe = cell2Faces[*ci].end();
fi != fe; ++fi)
{
for (auto i = faceVertices[*fi].begin(),
e = faceVertices[*fi].end();
i != e; ++i)
{
const double z = Opm::UgGridHelpers::
vertexCoordinates(grid, *i)[nd - 1];
if (z < span[0]) { span[0] = z; }
if (z > span[1]) { span[1] = z; }
}
} }
} }
} }
} // namespace Details } // namespace Details
/** /**
@ -587,64 +893,18 @@ phasePressures(const Grid& grid,
const CellRange& cells, const CellRange& cells,
const double grav = Opm::unit::gravity) const double grav = Opm::unit::gravity)
{ {
std::array<double,2> span =
{{ std::numeric_limits<double>::max(),
-std::numeric_limits<double>::max() }}; // Symm. about 0.
int ncell = 0; int ncell = 0;
{ auto span = std::array<double, 2>{};
// This code is only supported in three space dimensions Details::verticalExtent(grid, cells, ncell, span);
assert (Grid::dimensionworld == 3);
const int nd = Grid::dimensionworld; using pval = std::vector<double>;
auto press = std::vector<pval>
(FluidSystem::numPhases, pval(ncell, 0.0));
// Define vertical span as // Ensure gas/oil and oil/water contacts are within the span for the
// // phase pressure calculation.
// [minimum(node depth(cells)), maximum(node depth(cells))] span[0] = std::min(span[0], std::min(reg.zgoc(), reg.zwoc()));
// span[1] = std::max(span[1], std::max(reg.zgoc(), reg.zwoc()));
// Note: We use a sledgehammer approach--looping all
// the nodes of all the faces of all the 'cells'--to
// compute those bounds. This necessarily entails
// visiting some nodes (and faces) multiple times.
//
// Note: The implementation of 'RK4IVP<>' implicitly
// imposes the requirement that cell centroids are all
// within this vertical span. That requirement is not
// checked.
auto cell2Faces = Opm::UgGridHelpers::cell2Faces(grid);
auto faceVertices = Opm::UgGridHelpers::face2Vertices(grid);
for (typename CellRange::const_iterator
ci = cells.begin(), ce = cells.end();
ci != ce; ++ci, ++ncell)
{
for (auto fi=cell2Faces[*ci].begin(),
fe=cell2Faces[*ci].end();
fi != fe;
++fi)
{
for (auto i = faceVertices[*fi].begin(), e = faceVertices[*fi].end();
i != e; ++i)
{
const double z = Opm::UgGridHelpers::vertexCoordinates(grid, *i)[nd-1];
if (z < span[0]) { span[0] = z; }
if (z > span[1]) { span[1] = z; }
}
}
}
}
const int np = FluidSystem::numPhases; //reg.phaseUsage().numPhases;
typedef std::vector<double> pval;
std::vector<pval> press(np, pval(ncell, 0.0));
const double zwoc = reg.zwoc ();
const double zgoc = reg.zgoc ();
// make sure goc and woc is within the span for the phase pressure calculation
span[0] = std::min(span[0],zgoc);
span[1] = std::max(span[1],zwoc);
Details::equilibrateOWG<FluidSystem>(grid, reg, grav, span, cells, press); Details::equilibrateOWG<FluidSystem>(grid, reg, grav, span, cells, press);