Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bård Skaflestad 2012-09-04 13:58:43 +02:00
commit abd8973382
6 changed files with 246 additions and 203 deletions

View File

@ -18,7 +18,7 @@
*/ */
#include <opm/core/fluid/BlackoilPropertiesFromDeck.hpp> #include <opm/core/fluid/BlackoilPropertiesFromDeck.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
namespace Opm namespace Opm
{ {
@ -34,6 +34,21 @@ namespace Opm
} }
} }
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param)
{
rock_.init(deck, grid);
const int samples = param.getDefault("dead_tab_size", 1025);
pvt_.init(deck, samples);
satprops_.init(deck, grid, param);
if (pvt_.numPhases() != satprops_.numPhases()) {
THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
}
}
BlackoilPropertiesFromDeck::~BlackoilPropertiesFromDeck() BlackoilPropertiesFromDeck::~BlackoilPropertiesFromDeck()
{ {
} }

View File

@ -26,6 +26,7 @@
#include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp> #include <opm/core/fluid/blackoil/BlackoilPvtProperties.hpp>
#include <opm/core/fluid/SaturationPropsFromDeck.hpp> #include <opm/core/fluid/SaturationPropsFromDeck.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
struct UnstructuredGrid; struct UnstructuredGrid;
@ -38,12 +39,24 @@ namespace Opm
{ {
public: public:
/// Initialize from deck and grid. /// Initialize from deck and grid.
/// \param deck Deck input parser /// \param[in] deck Deck input parser
/// \param grid Grid to which property object applies, needed for the /// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid) /// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck. /// to logical cartesian indices consistent with the deck.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck, BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid); const UnstructuredGrid& grid);
/// Initialize from deck, grid and parameters.
/// \param[in] deck Deck input parser
/// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
/// \param[in] param Parameters. Accepted parameters include:
/// dead_tab_size (1025) number of uniform sample points for dead-oil pvt tables.
/// tab_size_kr (200) number of uniform sample points for saturation tables.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param);
/// Destructor. /// Destructor.
virtual ~BlackoilPropertiesFromDeck(); virtual ~BlackoilPropertiesFromDeck();

View File

@ -19,10 +19,12 @@
#ifndef OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED #ifndef OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED
#define OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED #define OPM_SATURATIONPROPSFROMDECK_HEADER_INCLUDED
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/eclipse/EclipseGridParser.hpp> #include <opm/core/eclipse/EclipseGridParser.hpp>
#include <opm/core/utility/UniformTableLinear.hpp> #include <opm/core/utility/UniformTableLinear.hpp>
#include <opm/core/fluid/blackoil/BlackoilPhases.hpp> #include <opm/core/fluid/blackoil/BlackoilPhases.hpp>
#include <opm/core/fluid/SatFuncStone2.hpp>
#include <opm/core/fluid/SatFuncSimple.hpp>
#include <vector> #include <vector>
struct UnstructuredGrid; struct UnstructuredGrid;
@ -44,6 +46,10 @@ namespace Opm
void init(const EclipseGridParser& deck, void init(const EclipseGridParser& deck,
const UnstructuredGrid& grid); const UnstructuredGrid& grid);
void init(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param);
/// \return P, the number of phases. /// \return P, the number of phases.
int numPhases() const; int numPhases() const;
@ -88,30 +94,11 @@ namespace Opm
private: private:
PhaseUsage phase_usage_; PhaseUsage phase_usage_;
class SatFuncSet typedef SatFuncSimple satfunc_t;
{ std::vector<satfunc_t> satfuncset_;
public:
void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
void evalPc(const double* s, double* pc) const;
void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
double smin_[PhaseUsage::MaxNumPhases];
double smax_[PhaseUsage::MaxNumPhases];
private:
PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
UniformTableLinear<double> krw_;
UniformTableLinear<double> krow_;
UniformTableLinear<double> pcow_;
UniformTableLinear<double> krg_;
UniformTableLinear<double> krog_;
UniformTableLinear<double> pcog_;
double krocw_; // = krow_(s_wc)
};
std::vector<SatFuncSet> satfuncset_;
std::vector<int> cell_to_func_; // = SATNUM - 1 std::vector<int> cell_to_func_; // = SATNUM - 1
const SatFuncSet& funcForCell(const int cell) const; const satfunc_t& funcForCell(const int cell) const;
}; };

View File

@ -47,7 +47,7 @@ namespace Opm
BlackoilPvtProperties(); BlackoilPvtProperties();
/// Initialize from deck. /// Initialize from deck.
void init(const EclipseGridParser& deck); void init(const EclipseGridParser& deck, const int samples = 16);
/// Number of active phases. /// Number of active phases.
int numPhases() const; int numPhases() const;

View File

@ -512,11 +512,11 @@ namespace Opm
State& state) State& state)
{ {
const int num_phases = props.numPhases(); const int num_phases = props.numPhases();
if (num_phases != 2) {
THROW("initStateFromDeck(): currently handling only two-phase scenarios.");
}
state.init(grid, num_phases); state.init(grid, num_phases);
if (deck.hasField("EQUIL")) { if (deck.hasField("EQUIL")) {
if (num_phases != 2) {
THROW("initStateFromDeck(): EQUIL-based init currently handling only two-phase scenarios.");
}
// Set saturations depending on oil-water contact. // Set saturations depending on oil-water contact.
const EQUIL& equil= deck.getEQUIL(); const EQUIL& equil= deck.getEQUIL();
if (equil.equil.size() != 1) { if (equil.equil.size() != 1) {
@ -535,11 +535,27 @@ namespace Opm
const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT"); const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT");
const std::vector<double>& p_deck = deck.getFloatingPointValue("PRESSURE"); const std::vector<double>& p_deck = deck.getFloatingPointValue("PRESSURE");
const int num_cells = grid.number_of_cells; const int num_cells = grid.number_of_cells;
for (int c = 0; c < num_cells; ++c) { if (num_phases == 2) {
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c]; for (int c = 0; c < num_cells; ++c) {
s[2*c] = sw_deck[c_deck]; int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
s[2*c + 1] = 1.0 - s[2*c]; s[2*c] = sw_deck[c_deck];
p[c] = p_deck[c_deck]; s[2*c + 1] = 1.0 - s[2*c];
p[c] = p_deck[c_deck];
}
} else if (num_phases == 3) {
if (!deck.hasField("SGAS")) {
THROW("initStateFromDeck(): missing SGAS keyword in 3-phase init (only SWAT and PRESSURE found).");
}
const std::vector<double>& sg_deck = deck.getFloatingPointValue("SGAS");
for (int c = 0; c < num_cells; ++c) {
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
s[3*c] = sw_deck[c_deck];
s[3*c + 1] = 1.0 - (sw_deck[c_deck] + sg_deck[c_deck]);
s[3*c + 2] = sg_deck[c_deck];
p[c] = p_deck[c_deck];
}
} else {
THROW("initStateFromDeck(): init with SWAT etc. only available with 2 or 3 phases.");
} }
} else { } else {
THROW("initStateFromDeck(): we must either have EQUIL, or both SWAT and PRESSURE."); THROW("initStateFromDeck(): we must either have EQUIL, or both SWAT and PRESSURE.");

View File

@ -40,14 +40,14 @@ namespace Opm
/// @param[out] porevol the pore volume by cell. /// @param[out] porevol the pore volume by cell.
void computePorevolume(const UnstructuredGrid& grid, void computePorevolume(const UnstructuredGrid& grid,
const double* porosity, const double* porosity,
std::vector<double>& porevol) std::vector<double>& porevol)
{ {
int num_cells = grid.number_of_cells; int num_cells = grid.number_of_cells;
porevol.resize(num_cells); porevol.resize(num_cells);
std::transform(porosity, porosity + num_cells, std::transform(porosity, porosity + num_cells,
grid.cell_volumes, grid.cell_volumes,
porevol.begin(), porevol.begin(),
std::multiplies<double>()); std::multiplies<double>());
} }
@ -98,20 +98,20 @@ namespace Opm
/// For each phase p, we compute /// For each phase p, we compute
/// sat_vol_p = sum_i s_p_i pv_i /// sat_vol_p = sum_i s_p_i pv_i
void computeSaturatedVol(const std::vector<double>& pv, void computeSaturatedVol(const std::vector<double>& pv,
const std::vector<double>& s, const std::vector<double>& s,
double* sat_vol) double* sat_vol)
{ {
const int num_cells = pv.size(); const int num_cells = pv.size();
const int np = s.size()/pv.size(); const int np = s.size()/pv.size();
if (int(s.size()) != num_cells*np) { if (int(s.size()) != num_cells*np) {
THROW("Sizes of s and pv vectors do not match."); THROW("Sizes of s and pv vectors do not match.");
} }
std::fill(sat_vol, sat_vol + np, 0.0); std::fill(sat_vol, sat_vol + np, 0.0);
for (int c = 0; c < num_cells; ++c) { for (int c = 0; c < num_cells; ++c) {
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
sat_vol[p] += pv[c]*s[np*c + p]; sat_vol[p] += pv[c]*s[np*c + p];
} }
} }
} }
@ -123,28 +123,28 @@ namespace Opm
/// For each phase p, we compute /// For each phase p, we compute
/// aver_sat_p = (sum_i s_p_i pv_i) / (sum_i pv_i). /// aver_sat_p = (sum_i s_p_i pv_i) / (sum_i pv_i).
void computeAverageSat(const std::vector<double>& pv, void computeAverageSat(const std::vector<double>& pv,
const std::vector<double>& s, const std::vector<double>& s,
double* aver_sat) double* aver_sat)
{ {
const int num_cells = pv.size(); const int num_cells = pv.size();
const int np = s.size()/pv.size(); const int np = s.size()/pv.size();
if (int(s.size()) != num_cells*np) { if (int(s.size()) != num_cells*np) {
THROW("Sizes of s and pv vectors do not match."); THROW("Sizes of s and pv vectors do not match.");
} }
double tot_pv = 0.0; double tot_pv = 0.0;
// Note that we abuse the output array to accumulate the // Note that we abuse the output array to accumulate the
// saturated pore volumes. // saturated pore volumes.
std::fill(aver_sat, aver_sat + np, 0.0); std::fill(aver_sat, aver_sat + np, 0.0);
for (int c = 0; c < num_cells; ++c) { for (int c = 0; c < num_cells; ++c) {
tot_pv += pv[c]; tot_pv += pv[c];
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
aver_sat[p] += pv[c]*s[np*c + p]; aver_sat[p] += pv[c]*s[np*c + p];
} }
} }
// Must divide by pore volumes to get saturations. // Must divide by pore volumes to get saturations.
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
aver_sat[p] /= tot_pv; aver_sat[p] /= tot_pv;
} }
} }
@ -161,38 +161,38 @@ namespace Opm
/// where P = s.size()/src.size(). /// where P = s.size()/src.size().
/// @param[out] produced must also point to a valid array with P elements. /// @param[out] produced must also point to a valid array with P elements.
void computeInjectedProduced(const IncompPropertiesInterface& props, void computeInjectedProduced(const IncompPropertiesInterface& props,
const std::vector<double>& s, const std::vector<double>& s,
const std::vector<double>& src, const std::vector<double>& src,
const double dt, const double dt,
double* injected, double* injected,
double* produced) double* produced)
{ {
const int num_cells = src.size(); const int num_cells = src.size();
const int np = s.size()/src.size(); const int np = s.size()/src.size();
if (int(s.size()) != num_cells*np) { if (int(s.size()) != num_cells*np) {
THROW("Sizes of s and src vectors do not match."); THROW("Sizes of s and src vectors do not match.");
} }
std::fill(injected, injected + np, 0.0); std::fill(injected, injected + np, 0.0);
std::fill(produced, produced + np, 0.0); std::fill(produced, produced + np, 0.0);
const double* visc = props.viscosity(); const double* visc = props.viscosity();
std::vector<double> mob(np); std::vector<double> mob(np);
for (int c = 0; c < num_cells; ++c) { for (int c = 0; c < num_cells; ++c) {
if (src[c] > 0.0) { if (src[c] > 0.0) {
injected[0] += src[c]*dt; injected[0] += src[c]*dt;
} else if (src[c] < 0.0) { } else if (src[c] < 0.0) {
const double flux = -src[c]*dt; const double flux = -src[c]*dt;
const double* sat = &s[np*c]; const double* sat = &s[np*c];
props.relperm(1, sat, &c, &mob[0], 0); props.relperm(1, sat, &c, &mob[0], 0);
double totmob = 0.0; double totmob = 0.0;
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
mob[p] /= visc[p]; mob[p] /= visc[p];
totmob += mob[p]; totmob += mob[p];
} }
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
produced[p] += (mob[p]/totmob)*flux; produced[p] += (mob[p]/totmob)*flux;
} }
} }
} }
} }
@ -203,9 +203,9 @@ namespace Opm
/// @param[in] s saturation values (for all phases) /// @param[in] s saturation values (for all phases)
/// @param[out] totmob total mobilities. /// @param[out] totmob total mobilities.
void computeTotalMobility(const Opm::IncompPropertiesInterface& props, void computeTotalMobility(const Opm::IncompPropertiesInterface& props,
const std::vector<int>& cells, const std::vector<int>& cells,
const std::vector<double>& s, const std::vector<double>& s,
std::vector<double>& totmob) std::vector<double>& totmob)
{ {
std::vector<double> pmobc; std::vector<double> pmobc;
@ -231,10 +231,10 @@ namespace Opm
/// @param[out] totmob total mobility /// @param[out] totmob total mobility
/// @param[out] omega fractional-flow weighted fluid densities. /// @param[out] omega fractional-flow weighted fluid densities.
void computeTotalMobilityOmega(const Opm::IncompPropertiesInterface& props, void computeTotalMobilityOmega(const Opm::IncompPropertiesInterface& props,
const std::vector<int>& cells, const std::vector<int>& cells,
const std::vector<double>& s, const std::vector<double>& s,
std::vector<double>& totmob, std::vector<double>& totmob,
std::vector<double>& omega) std::vector<double>& omega)
{ {
std::vector<double> pmobc; std::vector<double> pmobc;
@ -331,33 +331,33 @@ namespace Opm
/// (+) positive inflow of first phase (water) /// (+) positive inflow of first phase (water)
/// (-) negative total outflow of both phases /// (-) negative total outflow of both phases
void computeTransportSource(const UnstructuredGrid& grid, void computeTransportSource(const UnstructuredGrid& grid,
const std::vector<double>& src, const std::vector<double>& src,
const std::vector<double>& faceflux, const std::vector<double>& faceflux,
const double inflow_frac, const double inflow_frac,
const Wells* wells, const Wells* wells,
const std::vector<double>& well_perfrates, const std::vector<double>& well_perfrates,
std::vector<double>& transport_src) std::vector<double>& transport_src)
{ {
int nc = grid.number_of_cells; int nc = grid.number_of_cells;
transport_src.resize(nc); transport_src.resize(nc);
// Source term and boundary contributions. // Source term and boundary contributions.
for (int c = 0; c < nc; ++c) { for (int c = 0; c < nc; ++c) {
transport_src[c] = 0.0; transport_src[c] = 0.0;
transport_src[c] += src[c] > 0.0 ? inflow_frac*src[c] : src[c]; transport_src[c] += src[c] > 0.0 ? inflow_frac*src[c] : src[c];
for (int hf = grid.cell_facepos[c]; hf < grid.cell_facepos[c + 1]; ++hf) { for (int hf = grid.cell_facepos[c]; hf < grid.cell_facepos[c + 1]; ++hf) {
int f = grid.cell_faces[hf]; int f = grid.cell_faces[hf];
const int* f2c = &grid.face_cells[2*f]; const int* f2c = &grid.face_cells[2*f];
double bdy_influx = 0.0; double bdy_influx = 0.0;
if (f2c[0] == c && f2c[1] == -1) { if (f2c[0] == c && f2c[1] == -1) {
bdy_influx = -faceflux[f]; bdy_influx = -faceflux[f];
} else if (f2c[0] == -1 && f2c[1] == c) { } else if (f2c[0] == -1 && f2c[1] == c) {
bdy_influx = faceflux[f]; bdy_influx = faceflux[f];
} }
if (bdy_influx != 0.0) { if (bdy_influx != 0.0) {
transport_src[c] += bdy_influx > 0.0 ? inflow_frac*bdy_influx : bdy_influx; transport_src[c] += bdy_influx > 0.0 ? inflow_frac*bdy_influx : bdy_influx;
} }
} }
} }
// Well contributions. // Well contributions.
if (wells) { if (wells) {
@ -392,52 +392,52 @@ namespace Opm
/// @param[in] face_flux signed per-face fluxes /// @param[in] face_flux signed per-face fluxes
/// @param[out] cell_velocity the estimated velocities. /// @param[out] cell_velocity the estimated velocities.
void estimateCellVelocity(const UnstructuredGrid& grid, void estimateCellVelocity(const UnstructuredGrid& grid,
const std::vector<double>& face_flux, const std::vector<double>& face_flux,
std::vector<double>& cell_velocity) std::vector<double>& cell_velocity)
{ {
const int dim = grid.dimensions; const int dim = grid.dimensions;
cell_velocity.clear(); cell_velocity.clear();
cell_velocity.resize(grid.number_of_cells*dim, 0.0); cell_velocity.resize(grid.number_of_cells*dim, 0.0);
for (int face = 0; face < grid.number_of_faces; ++face) { for (int face = 0; face < grid.number_of_faces; ++face) {
int c[2] = { grid.face_cells[2*face], grid.face_cells[2*face + 1] }; int c[2] = { grid.face_cells[2*face], grid.face_cells[2*face + 1] };
const double* fc = &grid.face_centroids[face*dim]; const double* fc = &grid.face_centroids[face*dim];
double flux = face_flux[face]; double flux = face_flux[face];
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (c[i] >= 0) { if (c[i] >= 0) {
const double* cc = &grid.cell_centroids[c[i]*dim]; const double* cc = &grid.cell_centroids[c[i]*dim];
for (int d = 0; d < dim; ++d) { for (int d = 0; d < dim; ++d) {
double v_contrib = fc[d] - cc[d]; double v_contrib = fc[d] - cc[d];
v_contrib *= flux/grid.cell_volumes[c[i]]; v_contrib *= flux/grid.cell_volumes[c[i]];
cell_velocity[c[i]*dim + d] += (i == 0) ? v_contrib : -v_contrib; cell_velocity[c[i]*dim + d] += (i == 0) ? v_contrib : -v_contrib;
} }
} }
} }
} }
} }
/// Extract a vector of water saturations from a vector of /// Extract a vector of water saturations from a vector of
/// interleaved water and oil saturations. /// interleaved water and oil saturations.
void toWaterSat(const std::vector<double>& sboth, void toWaterSat(const std::vector<double>& sboth,
std::vector<double>& sw) std::vector<double>& sw)
{ {
int num = sboth.size()/2; int num = sboth.size()/2;
sw.resize(num); sw.resize(num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
sw[i] = sboth[2*i]; sw[i] = sboth[2*i];
} }
} }
/// Make a a vector of interleaved water and oil saturations from /// Make a a vector of interleaved water and oil saturations from
/// a vector of water saturations. /// a vector of water saturations.
void toBothSat(const std::vector<double>& sw, void toBothSat(const std::vector<double>& sw,
std::vector<double>& sboth) std::vector<double>& sboth)
{ {
int num = sw.size(); int num = sw.size();
sboth.resize(2*num); sboth.resize(2*num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
sboth[2*i] = sw[i]; sboth[2*i] = sw[i];
sboth[2*i + 1] = 1.0 - sw[i]; sboth[2*i + 1] = 1.0 - sw[i];
} }
} }
@ -450,30 +450,30 @@ namespace Opm
if (np != 2) { if (np != 2) {
THROW("wellsToSrc() requires a 2 phase case."); THROW("wellsToSrc() requires a 2 phase case.");
} }
src.resize(num_cells); src.resize(num_cells);
for (int w = 0; w < wells.number_of_wells; ++w) { for (int w = 0; w < wells.number_of_wells; ++w) {
const int cur = wells.ctrls[w]->current; const int cur = wells.ctrls[w]->current;
if (wells.ctrls[w]->num != 1) { if (wells.ctrls[w]->num != 1) {
MESSAGE("In wellsToSrc(): well has more than one control, all but current control will be ignored."); MESSAGE("In wellsToSrc(): well has more than one control, all but current control will be ignored.");
} }
if (wells.ctrls[w]->type[cur] != RESERVOIR_RATE) { if (wells.ctrls[w]->type[cur] != RESERVOIR_RATE) {
THROW("In wellsToSrc(): well is something other than RESERVOIR_RATE."); THROW("In wellsToSrc(): well is something other than RESERVOIR_RATE.");
} }
if (wells.well_connpos[w+1] - wells.well_connpos[w] != 1) { if (wells.well_connpos[w+1] - wells.well_connpos[w] != 1) {
THROW("In wellsToSrc(): well has multiple perforations."); THROW("In wellsToSrc(): well has multiple perforations.");
} }
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
if (wells.ctrls[w]->distr[np*cur + p] != 1.0) { if (wells.ctrls[w]->distr[np*cur + p] != 1.0) {
THROW("In wellsToSrc(): well not controlled on total rate."); THROW("In wellsToSrc(): well not controlled on total rate.");
} }
} }
double flow = wells.ctrls[w]->target[cur]; double flow = wells.ctrls[w]->target[cur];
if (wells.type[w] == INJECTOR) { if (wells.type[w] == INJECTOR) {
flow *= wells.comp_frac[np*w + 0]; // Obtaining water rate for inflow source. flow *= wells.comp_frac[np*w + 0]; // Obtaining water rate for inflow source.
} }
const double cell = wells.well_cells[wells.well_connpos[w]]; const double cell = wells.well_cells[wells.well_connpos[w]];
src[cell] = flow; src[cell] = flow;
} }
} }
@ -593,8 +593,10 @@ namespace Opm
{ {
int nw = well_bhp.size(); int nw = well_bhp.size();
ASSERT(nw == wells.number_of_wells); ASSERT(nw == wells.number_of_wells);
if (props.numPhases() != 2) { int np = props.numPhases();
THROW("WellReport for now assumes two phase flow."); const int max_np = 3;
if (np > max_np) {
THROW("WellReport for now assumes #phases <= " << max_np);
} }
const double* visc = props.viscosity(); const double* visc = props.viscosity();
std::vector<double> data_now; std::vector<double> data_now;
@ -605,7 +607,8 @@ namespace Opm
double well_rate_total = 0.0; double well_rate_total = 0.0;
double well_rate_water = 0.0; double well_rate_water = 0.0;
for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w + 1]; ++perf) { for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w + 1]; ++perf) {
const double perf_rate = well_perfrates[perf]*(unit::day/unit::second); const double perf_rate = unit::convert::to(well_perfrates[perf],
unit::cubic(unit::meter)/unit::day);
well_rate_total += perf_rate; well_rate_total += perf_rate;
if (perf_rate > 0.0) { if (perf_rate > 0.0) {
// Injection. // Injection.
@ -613,11 +616,14 @@ namespace Opm
} else { } else {
// Production. // Production.
const int cell = wells.well_cells[perf]; const int cell = wells.well_cells[perf];
double mob[2]; double mob[max_np];
props.relperm(1, &saturation[2*cell], &cell, mob, 0); props.relperm(1, &saturation[2*cell], &cell, mob, 0);
mob[0] /= visc[0]; double tmob = 0;
mob[1] /= visc[1]; for(int i = 0; i < np; ++i) {
const double fracflow = mob[0]/(mob[0] + mob[1]); mob[i] /= visc[i];
tmob += mob[i];
}
const double fracflow = mob[0]/tmob;
well_rate_water += perf_rate*fracflow; well_rate_water += perf_rate*fracflow;
} }
} }
@ -646,8 +652,10 @@ namespace Opm
// TODO: refactor, since this is almost identical to the other push(). // TODO: refactor, since this is almost identical to the other push().
int nw = well_bhp.size(); int nw = well_bhp.size();
ASSERT(nw == wells.number_of_wells); ASSERT(nw == wells.number_of_wells);
if (props.numPhases() != 2) { int np = props.numPhases();
THROW("WellReport for now assumes two phase flow."); const int max_np = 3;
if (np > max_np) {
THROW("WellReport for now assumes #phases <= " << max_np);
} }
std::vector<double> data_now; std::vector<double> data_now;
data_now.reserve(1 + 3*nw); data_now.reserve(1 + 3*nw);
@ -657,7 +665,8 @@ namespace Opm
double well_rate_total = 0.0; double well_rate_total = 0.0;
double well_rate_water = 0.0; double well_rate_water = 0.0;
for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w + 1]; ++perf) { for (int perf = wells.well_connpos[w]; perf < wells.well_connpos[w + 1]; ++perf) {
const double perf_rate = well_perfrates[perf]*(unit::day/unit::second); const double perf_rate = unit::convert::to(well_perfrates[perf],
unit::cubic(unit::meter)/unit::day);
well_rate_total += perf_rate; well_rate_total += perf_rate;
if (perf_rate > 0.0) { if (perf_rate > 0.0) {
// Injection. // Injection.
@ -665,13 +674,16 @@ namespace Opm
} else { } else {
// Production. // Production.
const int cell = wells.well_cells[perf]; const int cell = wells.well_cells[perf];
double mob[2]; double mob[max_np];
props.relperm(1, &s[2*cell], &cell, mob, 0); props.relperm(1, &s[np*cell], &cell, mob, 0);
double visc[2]; double visc[max_np];
props.viscosity(1, &p[cell], &z[2*cell], &cell, visc, 0); props.viscosity(1, &p[cell], &z[np*cell], &cell, visc, 0);
mob[0] /= visc[0]; double tmob = 0;
mob[1] /= visc[1]; for(int i = 0; i < np; ++i) {
const double fracflow = mob[0]/(mob[0] + mob[1]); mob[i] /= visc[i];
tmob += mob[i];
}
const double fracflow = mob[0]/(tmob);
well_rate_water += perf_rate*fracflow; well_rate_water += perf_rate*fracflow;
} }
} }