2016-04-06 08:23:43 -05:00
|
|
|
/*
|
|
|
|
Copyright 2016 SINTEF ICT, Applied Mathematics.
|
2016-04-06 08:31:58 -05:00
|
|
|
Copyright 2016 Statoil ASA.
|
2016-04-06 08:23:43 -05:00
|
|
|
|
|
|
|
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 3 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <opm/autodiff/StandardWells.hpp>
|
2016-04-08 09:05:56 -05:00
|
|
|
#include <opm/autodiff/WellDensitySegmented.hpp>
|
2016-04-06 08:23:43 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-07 09:17:25 -05:00
|
|
|
|
2016-04-06 08:23:43 -05:00
|
|
|
namespace Opm
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::
|
2016-04-06 08:23:43 -05:00
|
|
|
WellOps::WellOps(const Wells* wells)
|
|
|
|
: w2p(),
|
|
|
|
p2w(),
|
|
|
|
well_cells()
|
|
|
|
{
|
|
|
|
if( wells )
|
|
|
|
{
|
|
|
|
w2p = Eigen::SparseMatrix<double>(wells->well_connpos[ wells->number_of_wells ], wells->number_of_wells);
|
|
|
|
p2w = Eigen::SparseMatrix<double>(wells->number_of_wells, wells->well_connpos[ wells->number_of_wells ]);
|
|
|
|
|
|
|
|
const int nw = wells->number_of_wells;
|
|
|
|
const int* const wpos = wells->well_connpos;
|
|
|
|
|
|
|
|
typedef Eigen::Triplet<double> Tri;
|
|
|
|
|
|
|
|
std::vector<Tri> scatter, gather;
|
|
|
|
scatter.reserve(wpos[nw]);
|
|
|
|
gather .reserve(wpos[nw]);
|
|
|
|
|
|
|
|
for (int w = 0, i = 0; w < nw; ++w) {
|
|
|
|
for (; i < wpos[ w + 1 ]; ++i) {
|
|
|
|
scatter.push_back(Tri(i, w, 1.0));
|
|
|
|
gather .push_back(Tri(w, i, 1.0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
w2p.setFromTriplets(scatter.begin(), scatter.end());
|
|
|
|
p2w.setFromTriplets(gather .begin(), gather .end());
|
|
|
|
|
|
|
|
well_cells.assign(wells->well_cells, wells->well_cells + wells->well_connpos[wells->number_of_wells]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::StandardWells(const Wells* wells_arg)
|
2016-04-06 08:23:43 -05:00
|
|
|
: wells_(wells_arg)
|
|
|
|
, wops_(wells_arg)
|
|
|
|
, well_perforation_densities_(Vector())
|
|
|
|
, well_perforation_pressure_diffs_(Vector())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
const Wells& StandardWells::wells() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
assert(wells_ != 0);
|
|
|
|
return *(wells_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
bool StandardWells::wellsActive() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return wells_active_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
void StandardWells::setWellsActive(const bool wells_active)
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
wells_active_ = wells_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
bool StandardWells::localWellsActive() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return wells_ ? (wells_->number_of_wells > 0 ) : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
const StandardWells::WellOps&
|
|
|
|
StandardWells::wellOps() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return wops_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 03:20:11 -05:00
|
|
|
Vector& StandardWells::wellPerforationDensities()
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return well_perforation_densities_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-07 08:41:08 -05:00
|
|
|
const Vector&
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::wellPerforationDensities() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return well_perforation_densities_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-07 08:41:08 -05:00
|
|
|
Vector&
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::wellPerforationPressureDiffs()
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return well_perforation_pressure_diffs_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-07 08:41:08 -05:00
|
|
|
const Vector&
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::wellPerforationPressureDiffs() const
|
2016-04-06 08:23:43 -05:00
|
|
|
{
|
|
|
|
return well_perforation_pressure_diffs_;
|
|
|
|
}
|
|
|
|
|
2016-04-07 09:17:25 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class SolutionState, class WellState>
|
|
|
|
void
|
2016-04-08 03:20:11 -05:00
|
|
|
StandardWells::
|
2016-04-07 09:17:25 -05:00
|
|
|
computePropertiesForWellConnectionPressures(const SolutionState& state,
|
|
|
|
const WellState& xw,
|
|
|
|
const BlackoilPropsAdInterface& fluid,
|
|
|
|
const std::vector<bool>& active,
|
|
|
|
const std::vector<PhasePresence>& pc,
|
|
|
|
std::vector<double>& b_perf,
|
|
|
|
std::vector<double>& rsmax_perf,
|
|
|
|
std::vector<double>& rvmax_perf,
|
|
|
|
std::vector<double>& surf_dens_perf)
|
|
|
|
{
|
|
|
|
const int nperf = wells().well_connpos[wells().number_of_wells];
|
|
|
|
const int nw = wells().number_of_wells;
|
|
|
|
|
|
|
|
// Compute the average pressure in each well block
|
|
|
|
const Vector perf_press = Eigen::Map<const Vector>(xw.perfPress().data(), nperf);
|
|
|
|
Vector avg_press = perf_press*0;
|
|
|
|
for (int w = 0; w < nw; ++w) {
|
|
|
|
for (int perf = wells().well_connpos[w]; perf < wells().well_connpos[w+1]; ++perf) {
|
|
|
|
const double p_above = perf == wells().well_connpos[w] ? state.bhp.value()[w] : perf_press[perf - 1];
|
|
|
|
const double p_avg = (perf_press[perf] + p_above)/2;
|
|
|
|
avg_press[perf] = p_avg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<int>& well_cells = wellOps().well_cells;
|
|
|
|
|
|
|
|
// Use cell values for the temperature as the wells don't knows its temperature yet.
|
|
|
|
const ADB perf_temp = subset(state.temperature, well_cells);
|
|
|
|
|
|
|
|
// Compute b, rsmax, rvmax values for perforations.
|
|
|
|
// Evaluate the properties using average well block pressures
|
|
|
|
// and cell values for rs, rv, phase condition and temperature.
|
|
|
|
const ADB avg_press_ad = ADB::constant(avg_press);
|
|
|
|
std::vector<PhasePresence> perf_cond(nperf);
|
|
|
|
// const std::vector<PhasePresence>& pc = phaseCondition();
|
|
|
|
for (int perf = 0; perf < nperf; ++perf) {
|
|
|
|
perf_cond[perf] = pc[well_cells[perf]];
|
|
|
|
}
|
|
|
|
const PhaseUsage& pu = fluid.phaseUsage();
|
|
|
|
DataBlock b(nperf, pu.num_phases);
|
|
|
|
if (pu.phase_used[BlackoilPhases::Aqua]) {
|
|
|
|
const Vector bw = fluid.bWat(avg_press_ad, perf_temp, well_cells).value();
|
|
|
|
b.col(pu.phase_pos[BlackoilPhases::Aqua]) = bw;
|
|
|
|
}
|
|
|
|
assert(active[Oil]);
|
|
|
|
const Vector perf_so = subset(state.saturation[pu.phase_pos[Oil]].value(), well_cells);
|
|
|
|
if (pu.phase_used[BlackoilPhases::Liquid]) {
|
|
|
|
const ADB perf_rs = subset(state.rs, well_cells);
|
|
|
|
const Vector bo = fluid.bOil(avg_press_ad, perf_temp, perf_rs, perf_cond, well_cells).value();
|
|
|
|
b.col(pu.phase_pos[BlackoilPhases::Liquid]) = bo;
|
|
|
|
// const V rssat = fluidRsSat(avg_press, perf_so, well_cells);
|
|
|
|
const Vector rssat = fluid.rsSat(ADB::constant(avg_press), ADB::constant(perf_so), well_cells).value();
|
|
|
|
rsmax_perf.assign(rssat.data(), rssat.data() + nperf);
|
|
|
|
} else {
|
|
|
|
rsmax_perf.assign(nperf, 0.0);
|
|
|
|
}
|
|
|
|
if (pu.phase_used[BlackoilPhases::Vapour]) {
|
|
|
|
const ADB perf_rv = subset(state.rv, well_cells);
|
|
|
|
const Vector bg = fluid.bGas(avg_press_ad, perf_temp, perf_rv, perf_cond, well_cells).value();
|
|
|
|
b.col(pu.phase_pos[BlackoilPhases::Vapour]) = bg;
|
|
|
|
// const V rvsat = fluidRvSat(avg_press, perf_so, well_cells);
|
|
|
|
const Vector rvsat = fluid.rvSat(ADB::constant(avg_press), ADB::constant(perf_so), well_cells).value();
|
|
|
|
rvmax_perf.assign(rvsat.data(), rvsat.data() + nperf);
|
|
|
|
} else {
|
|
|
|
rvmax_perf.assign(nperf, 0.0);
|
|
|
|
}
|
|
|
|
// b is row major, so can just copy data.
|
|
|
|
b_perf.assign(b.data(), b.data() + nperf * pu.num_phases);
|
|
|
|
|
|
|
|
// Surface density.
|
|
|
|
// The compute density segment wants the surface densities as
|
|
|
|
// an np * number of wells cells array
|
|
|
|
Vector rho = superset(fluid.surfaceDensity(0 , well_cells), Span(nperf, pu.num_phases, 0), nperf*pu.num_phases);
|
|
|
|
for (int phase = 1; phase < pu.num_phases; ++phase) {
|
|
|
|
rho += superset(fluid.surfaceDensity(phase , well_cells), Span(nperf, pu.num_phases, phase), nperf*pu.num_phases);
|
|
|
|
}
|
|
|
|
surf_dens_perf.assign(rho.data(), rho.data() + nperf * pu.num_phases);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-04-08 09:48:31 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-08 09:05:56 -05:00
|
|
|
template <class WellState>
|
|
|
|
void
|
|
|
|
StandardWells::
|
|
|
|
computeWellConnectionDensitesPressures(const WellState& xw,
|
|
|
|
const BlackoilPropsAdInterface& fluid,
|
|
|
|
const std::vector<double>& b_perf,
|
|
|
|
const std::vector<double>& rsmax_perf,
|
|
|
|
const std::vector<double>& rvmax_perf,
|
|
|
|
const std::vector<double>& surf_dens_perf,
|
|
|
|
const std::vector<double>& depth_perf,
|
|
|
|
const double grav)
|
|
|
|
{
|
|
|
|
// Compute densities
|
|
|
|
std::vector<double> cd =
|
|
|
|
WellDensitySegmented::computeConnectionDensities(
|
|
|
|
wells(), xw, fluid.phaseUsage(),
|
|
|
|
b_perf, rsmax_perf, rvmax_perf, surf_dens_perf);
|
|
|
|
|
|
|
|
const int nperf = wells().well_connpos[wells().number_of_wells];
|
|
|
|
|
|
|
|
// Compute pressure deltas
|
|
|
|
std::vector<double> cdp =
|
|
|
|
WellDensitySegmented::computeConnectionPressureDelta(
|
|
|
|
wells(), depth_perf, cd, grav);
|
|
|
|
|
|
|
|
// Store the results
|
|
|
|
well_perforation_densities_ = Eigen::Map<const Vector>(cd.data(), nperf);
|
|
|
|
well_perforation_pressure_diffs_ = Eigen::Map<const Vector>(cdp.data(), nperf);
|
|
|
|
}
|
2016-04-07 09:17:25 -05:00
|
|
|
|
2016-04-08 09:48:31 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class ReservoirResidualQuant>
|
|
|
|
void
|
|
|
|
StandardWells::
|
|
|
|
extractWellPerfProperties(const std::vector<ReservoirResidualQuant>& rq,
|
|
|
|
const int np,
|
|
|
|
std::vector<ADB>& mob_perfcells,
|
|
|
|
std::vector<ADB>& b_perfcells) const
|
|
|
|
{
|
|
|
|
// If we have wells, extract the mobilities and b-factors for
|
|
|
|
// the well-perforated cells.
|
|
|
|
if ( !localWellsActive() ) {
|
|
|
|
mob_perfcells.clear();
|
|
|
|
b_perfcells.clear();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
const std::vector<int>& well_cells = wellOps().well_cells;
|
|
|
|
mob_perfcells.resize(np, ADB::null());
|
|
|
|
b_perfcells.resize(np, ADB::null());
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
mob_perfcells[phase] = subset(rq[phase].mob, well_cells);
|
|
|
|
b_perfcells[phase] = subset(rq[phase].b, well_cells);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-08 10:26:07 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class SolutionState>
|
|
|
|
void
|
|
|
|
StandardWells::
|
|
|
|
computeWellFlux(const SolutionState& state,
|
|
|
|
const Opm::PhaseUsage& pu,
|
|
|
|
const std::vector<bool>& active,
|
|
|
|
const std::vector<ADB>& mob_perfcells,
|
|
|
|
const std::vector<ADB>& b_perfcells,
|
|
|
|
Vector& aliveWells,
|
|
|
|
std::vector<ADB>& cq_s) const
|
|
|
|
{
|
|
|
|
if( ! localWellsActive() ) return ;
|
|
|
|
|
|
|
|
const int np = wells().number_of_phases;
|
|
|
|
const int nw = wells().number_of_wells;
|
|
|
|
const int nperf = wells().well_connpos[nw];
|
|
|
|
Vector Tw = Eigen::Map<const Vector>(wells().WI, nperf);
|
|
|
|
const std::vector<int>& well_cells = wellOps().well_cells;
|
|
|
|
|
|
|
|
// pressure diffs computed already (once per step, not changing per iteration)
|
|
|
|
const Vector& cdp = wellPerforationPressureDiffs();
|
|
|
|
// Extract needed quantities for the perforation cells
|
|
|
|
const ADB& p_perfcells = subset(state.pressure, well_cells);
|
|
|
|
const ADB& rv_perfcells = subset(state.rv, well_cells);
|
|
|
|
const ADB& rs_perfcells = subset(state.rs, well_cells);
|
|
|
|
|
|
|
|
// Perforation pressure
|
|
|
|
const ADB perfpressure = (wellOps().w2p * state.bhp) + cdp;
|
|
|
|
|
|
|
|
// Pressure drawdown (also used to determine direction of flow)
|
|
|
|
const ADB drawdown = p_perfcells - perfpressure;
|
|
|
|
|
|
|
|
// Compute vectors with zero and ones that
|
|
|
|
// selects the wanted quantities.
|
|
|
|
|
|
|
|
// selects injection perforations
|
|
|
|
Vector selectInjectingPerforations = Vector::Zero(nperf);
|
|
|
|
// selects producing perforations
|
|
|
|
Vector selectProducingPerforations = Vector::Zero(nperf);
|
|
|
|
for (int c = 0; c < nperf; ++c){
|
|
|
|
if (drawdown.value()[c] < 0)
|
|
|
|
selectInjectingPerforations[c] = 1;
|
|
|
|
else
|
|
|
|
selectProducingPerforations[c] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle cross flow
|
|
|
|
const Vector numInjectingPerforations = (wellOps().p2w * ADB::constant(selectInjectingPerforations)).value();
|
|
|
|
const Vector numProducingPerforations = (wellOps().p2w * ADB::constant(selectProducingPerforations)).value();
|
|
|
|
for (int w = 0; w < nw; ++w) {
|
|
|
|
if (!wells().allow_cf[w]) {
|
|
|
|
for (int perf = wells().well_connpos[w] ; perf < wells().well_connpos[w+1]; ++perf) {
|
|
|
|
// Crossflow is not allowed; reverse flow is prevented.
|
|
|
|
// At least one of the perforation must be open in order to have a meeningful
|
|
|
|
// equation to solve. For the special case where all perforations have reverse flow,
|
|
|
|
// and the target rate is non-zero all of the perforations are keept open.
|
|
|
|
if (wells().type[w] == INJECTOR && numInjectingPerforations[w] > 0) {
|
|
|
|
selectProducingPerforations[perf] = 0.0;
|
|
|
|
} else if (wells().type[w] == PRODUCER && numProducingPerforations[w] > 0 ){
|
|
|
|
selectInjectingPerforations[perf] = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// HANDLE FLOW INTO WELLBORE
|
|
|
|
// compute phase volumetric rates at standard conditions
|
|
|
|
std::vector<ADB> cq_ps(np, ADB::null());
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
const ADB cq_p = -(selectProducingPerforations * Tw) * (mob_perfcells[phase] * drawdown);
|
|
|
|
cq_ps[phase] = b_perfcells[phase] * cq_p;
|
|
|
|
}
|
|
|
|
if (active[Oil] && active[Gas]) {
|
|
|
|
const int oilpos = pu.phase_pos[Oil];
|
|
|
|
const int gaspos = pu.phase_pos[Gas];
|
|
|
|
const ADB cq_psOil = cq_ps[oilpos];
|
|
|
|
const ADB cq_psGas = cq_ps[gaspos];
|
|
|
|
cq_ps[gaspos] += rs_perfcells * cq_psOil;
|
|
|
|
cq_ps[oilpos] += rv_perfcells * cq_psGas;
|
|
|
|
}
|
|
|
|
|
|
|
|
// HANDLE FLOW OUT FROM WELLBORE
|
|
|
|
// Using total mobilities
|
|
|
|
ADB total_mob = mob_perfcells[0];
|
|
|
|
for (int phase = 1; phase < np; ++phase) {
|
|
|
|
total_mob += mob_perfcells[phase];
|
|
|
|
}
|
|
|
|
// injection perforations total volume rates
|
|
|
|
const ADB cqt_i = -(selectInjectingPerforations * Tw) * (total_mob * drawdown);
|
|
|
|
|
|
|
|
// compute wellbore mixture for injecting perforations
|
|
|
|
// The wellbore mixture depends on the inflow from the reservoar
|
|
|
|
// and the well injection rates.
|
|
|
|
|
|
|
|
// compute avg. and total wellbore phase volumetric rates at standard conds
|
|
|
|
const DataBlock compi = Eigen::Map<const DataBlock>(wells().comp_frac, nw, np);
|
|
|
|
std::vector<ADB> wbq(np, ADB::null());
|
|
|
|
ADB wbqt = ADB::constant(Vector::Zero(nw));
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
const ADB& q_ps = wellOps().p2w * cq_ps[phase];
|
|
|
|
const ADB& q_s = subset(state.qs, Span(nw, 1, phase*nw));
|
|
|
|
Selector<double> injectingPhase_selector(q_s.value(), Selector<double>::GreaterZero);
|
|
|
|
const int pos = pu.phase_pos[phase];
|
|
|
|
wbq[phase] = (compi.col(pos) * injectingPhase_selector.select(q_s,ADB::constant(Vector::Zero(nw)))) - q_ps;
|
|
|
|
wbqt += wbq[phase];
|
|
|
|
}
|
|
|
|
// compute wellbore mixture at standard conditions.
|
|
|
|
Selector<double> notDeadWells_selector(wbqt.value(), Selector<double>::Zero);
|
|
|
|
std::vector<ADB> cmix_s(np, ADB::null());
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
const int pos = pu.phase_pos[phase];
|
|
|
|
cmix_s[phase] = wellOps().w2p * notDeadWells_selector.select(ADB::constant(compi.col(pos)), wbq[phase]/wbqt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute volume ratio between connection at standard conditions
|
|
|
|
ADB volumeRatio = ADB::constant(Vector::Zero(nperf));
|
|
|
|
const ADB d = Vector::Constant(nperf,1.0) - rv_perfcells * rs_perfcells;
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
ADB tmp = cmix_s[phase];
|
|
|
|
|
|
|
|
if (phase == Oil && active[Gas]) {
|
|
|
|
const int gaspos = pu.phase_pos[Gas];
|
|
|
|
tmp -= rv_perfcells * cmix_s[gaspos] / d;
|
|
|
|
}
|
|
|
|
if (phase == Gas && active[Oil]) {
|
|
|
|
const int oilpos = pu.phase_pos[Oil];
|
|
|
|
tmp -= rs_perfcells * cmix_s[oilpos] / d;
|
|
|
|
}
|
|
|
|
volumeRatio += tmp / b_perfcells[phase];
|
|
|
|
}
|
|
|
|
|
|
|
|
// injecting connections total volumerates at standard conditions
|
|
|
|
ADB cqt_is = cqt_i/volumeRatio;
|
|
|
|
|
|
|
|
// connection phase volumerates at standard conditions
|
|
|
|
cq_s.resize(np, ADB::null());
|
|
|
|
for (int phase = 0; phase < np; ++phase) {
|
|
|
|
cq_s[phase] = cq_ps[phase] + cmix_s[phase]*cqt_is;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for dead wells (used in the well controll equations)
|
|
|
|
aliveWells = Vector::Constant(nw, 1.0);
|
|
|
|
for (int w = 0; w < nw; ++w) {
|
|
|
|
if (wbqt.value()[w] == 0) {
|
|
|
|
aliveWells[w] = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 08:23:43 -05:00
|
|
|
}
|