mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Add all present controls to wells, not just the active one.
Some restructuring to support more proper well handling, esp. group control and surface rate controls in general.
This commit is contained in:
parent
432b9d4473
commit
d7512bdeb6
@ -25,6 +25,7 @@
|
|||||||
#include <opm/core/utility/ErrorMacros.hpp>
|
#include <opm/core/utility/ErrorMacros.hpp>
|
||||||
#include <opm/core/utility/Units.hpp>
|
#include <opm/core/utility/Units.hpp>
|
||||||
#include <opm/core/WellCollection.hpp>
|
#include <opm/core/WellCollection.hpp>
|
||||||
|
#include <opm/core/fluid/blackoil/phaseUsageFromDeck.hpp>
|
||||||
|
|
||||||
#include <tr1/array>
|
#include <tr1/array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -36,84 +37,94 @@ namespace
|
|||||||
|
|
||||||
struct WellData
|
struct WellData
|
||||||
{
|
{
|
||||||
WellType type;
|
WellType type;
|
||||||
WellControlType control;
|
// WellControlType control;
|
||||||
double target;
|
// double target;
|
||||||
double reference_bhp_depth;
|
double reference_bhp_depth;
|
||||||
SurfaceComponent injected_phase;
|
// Opm::InjectionSpecification::InjectorType injected_phase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct PerfData
|
struct PerfData
|
||||||
{
|
{
|
||||||
int cell;
|
int cell;
|
||||||
double well_index;
|
double well_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace ProductionControl
|
||||||
int prod_control_mode(const std::string& control)
|
|
||||||
{
|
{
|
||||||
const int num_prod_control_modes = 8;
|
enum Mode { ORAT, WRAT, GRAT,
|
||||||
static std::string prod_control_modes[num_prod_control_modes] =
|
LRAT, CRAT, RESV,
|
||||||
{std::string("ORAT"), std::string("WRAT"), std::string("GRAT"),
|
BHP, THP, GRUP };
|
||||||
std::string("LRAT"), std::string("RESV"), std::string("BHP"),
|
Mode mode(const std::string& control)
|
||||||
std::string("THP"), std::string("GRUP") };
|
{
|
||||||
int m = -1;
|
const int num_prod_control_modes = 9;
|
||||||
for (int i=0; i<num_prod_control_modes; ++i) {
|
static std::string prod_control_modes[num_prod_control_modes] =
|
||||||
if (control == prod_control_modes[i]) {
|
{std::string("ORAT"), std::string("WRAT"), std::string("GRAT"),
|
||||||
m = i;
|
std::string("LRAT"), std::string("CRAT"), std::string("RESV"),
|
||||||
break;
|
std::string("BHP"), std::string("THP"), std::string("GRUP") };
|
||||||
}
|
int m = -1;
|
||||||
}
|
for (int i=0; i<num_prod_control_modes; ++i) {
|
||||||
if (m >= 0) {
|
if (control == prod_control_modes[i]) {
|
||||||
return m;
|
m = i;
|
||||||
} else {
|
break;
|
||||||
THROW("Unknown well control mode = " << control << " in input file");
|
}
|
||||||
}
|
}
|
||||||
}
|
if (m >= 0) {
|
||||||
|
return static_cast<Mode>(m);
|
||||||
|
} else {
|
||||||
|
THROW("Unknown well control mode = " << control << " in input file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace ProductionControl
|
||||||
|
|
||||||
|
|
||||||
int inje_control_mode(const std::string& control)
|
namespace InjectionControl
|
||||||
{
|
{
|
||||||
const int num_inje_control_modes = 5;
|
enum Mode { RATE, RESV, BHP,
|
||||||
static std::string inje_control_modes[num_inje_control_modes] =
|
THP, GRUP };
|
||||||
{std::string("RATE"), std::string("RESV"), std::string("BHP"),
|
Mode mode(const std::string& control)
|
||||||
std::string("THP"), std::string("GRUP") };
|
{
|
||||||
int m = -1;
|
const int num_inje_control_modes = 5;
|
||||||
for (int i=0; i<num_inje_control_modes; ++i) {
|
static std::string inje_control_modes[num_inje_control_modes] =
|
||||||
if (control == inje_control_modes[i]) {
|
{std::string("RATE"), std::string("RESV"), std::string("BHP"),
|
||||||
m = i;
|
std::string("THP"), std::string("GRUP") };
|
||||||
break;
|
int m = -1;
|
||||||
}
|
for (int i=0; i<num_inje_control_modes; ++i) {
|
||||||
}
|
if (control == inje_control_modes[i]) {
|
||||||
|
m = i;
|
||||||
if (m >= 0) {
|
break;
|
||||||
return m;
|
}
|
||||||
} else {
|
}
|
||||||
THROW("Unknown well control mode = " << control << " in input file");
|
|
||||||
}
|
if (m >= 0) {
|
||||||
}
|
return static_cast<Mode>(m);
|
||||||
|
} else {
|
||||||
|
THROW("Unknown well control mode = " << control << " in input file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace InjectionControl
|
||||||
|
|
||||||
|
|
||||||
std::tr1::array<double, 3> getCubeDim(const UnstructuredGrid& grid, int cell)
|
std::tr1::array<double, 3> getCubeDim(const UnstructuredGrid& grid, int cell)
|
||||||
{
|
{
|
||||||
using namespace std;
|
using namespace std;
|
||||||
tr1::array<double, 3> cube;
|
tr1::array<double, 3> cube;
|
||||||
int num_local_faces = grid.cell_facepos[cell + 1] - grid.cell_facepos[cell];
|
int num_local_faces = grid.cell_facepos[cell + 1] - grid.cell_facepos[cell];
|
||||||
vector<double> x(num_local_faces);
|
vector<double> x(num_local_faces);
|
||||||
vector<double> y(num_local_faces);
|
vector<double> y(num_local_faces);
|
||||||
vector<double> z(num_local_faces);
|
vector<double> z(num_local_faces);
|
||||||
for (int lf=0; lf<num_local_faces; ++ lf) {
|
for (int lf=0; lf<num_local_faces; ++ lf) {
|
||||||
int face = grid.cell_faces[grid.cell_facepos[cell] + lf];
|
int face = grid.cell_faces[grid.cell_facepos[cell] + lf];
|
||||||
const double* centroid = &grid.face_centroids[grid.dimensions*face];
|
const double* centroid = &grid.face_centroids[grid.dimensions*face];
|
||||||
x[lf] = centroid[0];
|
x[lf] = centroid[0];
|
||||||
y[lf] = centroid[1];
|
y[lf] = centroid[1];
|
||||||
z[lf] = centroid[2];
|
z[lf] = centroid[2];
|
||||||
}
|
}
|
||||||
cube[0] = *max_element(x.begin(), x.end()) - *min_element(x.begin(), x.end());
|
cube[0] = *max_element(x.begin(), x.end()) - *min_element(x.begin(), x.end());
|
||||||
cube[1] = *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end());
|
cube[1] = *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end());
|
||||||
cube[2] = *max_element(z.begin(), z.end()) - *min_element(z.begin(), z.end());
|
cube[2] = *max_element(z.begin(), z.end()) - *min_element(z.begin(), z.end());
|
||||||
return cube;
|
return cube;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the Peaceman well model to compute well indices.
|
// Use the Peaceman well model to compute well indices.
|
||||||
@ -123,43 +134,43 @@ namespace
|
|||||||
// cell_permeability is the permeability tensor of the given cell.
|
// cell_permeability is the permeability tensor of the given cell.
|
||||||
// returns the well index of the cell.
|
// returns the well index of the cell.
|
||||||
double computeWellIndex(const double radius,
|
double computeWellIndex(const double radius,
|
||||||
const std::tr1::array<double, 3>& cubical,
|
const std::tr1::array<double, 3>& cubical,
|
||||||
const double* cell_permeability,
|
const double* cell_permeability,
|
||||||
const double skin_factor)
|
const double skin_factor)
|
||||||
{
|
{
|
||||||
using namespace std;
|
using namespace std;
|
||||||
// sse: Using the Peaceman model.
|
// sse: Using the Peaceman model.
|
||||||
// NOTE: The formula is valid for cartesian grids, so the result can be a bit
|
// NOTE: The formula is valid for cartesian grids, so the result can be a bit
|
||||||
// (in worst case: there is no upper bound for the error) off the mark.
|
// (in worst case: there is no upper bound for the error) off the mark.
|
||||||
const double permx = cell_permeability[0];
|
const double permx = cell_permeability[0];
|
||||||
const double permy = cell_permeability[3*1 + 1];
|
const double permy = cell_permeability[3*1 + 1];
|
||||||
double effective_perm = sqrt(permx*permy);
|
double effective_perm = sqrt(permx*permy);
|
||||||
// sse: The formula for r_0 can be found on page 39 of
|
// sse: The formula for r_0 can be found on page 39 of
|
||||||
// "Well Models for Mimetic Finite Differerence Methods and Improved Representation
|
// "Well Models for Mimetic Finite Differerence Methods and Improved Representation
|
||||||
// of Wells in Multiscale Methods" by Ingeborg Skjelkvåle Ligaarden.
|
// of Wells in Multiscale Methods" by Ingeborg Skjelkvåle Ligaarden.
|
||||||
assert(permx > 0.0);
|
assert(permx > 0.0);
|
||||||
assert(permy > 0.0);
|
assert(permy > 0.0);
|
||||||
double kxoy = permx / permy;
|
double kxoy = permx / permy;
|
||||||
double kyox = permy / permx;
|
double kyox = permy / permx;
|
||||||
double r0_denominator = pow(kyox, 0.25) + pow(kxoy, 0.25);
|
double r0_denominator = pow(kyox, 0.25) + pow(kxoy, 0.25);
|
||||||
double r0_numerator = sqrt((sqrt(kyox)*cubical[0]*cubical[0]) +
|
double r0_numerator = sqrt((sqrt(kyox)*cubical[0]*cubical[0]) +
|
||||||
(sqrt(kxoy)*cubical[1]*cubical[1]));
|
(sqrt(kxoy)*cubical[1]*cubical[1]));
|
||||||
assert(r0_denominator > 0.0);
|
assert(r0_denominator > 0.0);
|
||||||
double r0 = 0.28 * r0_numerator / r0_denominator;
|
double r0 = 0.28 * r0_numerator / r0_denominator;
|
||||||
assert(radius > 0.0);
|
assert(radius > 0.0);
|
||||||
assert(r0 > 0.0);
|
assert(r0 > 0.0);
|
||||||
if (r0 < radius) {
|
if (r0 < radius) {
|
||||||
std::cout << "ERROR: Too big well radius detected.";
|
std::cout << "ERROR: Too big well radius detected.";
|
||||||
std::cout << "Specified well radius is " << radius
|
std::cout << "Specified well radius is " << radius
|
||||||
<< " while r0 is " << r0 << ".\n";
|
<< " while r0 is " << r0 << ".\n";
|
||||||
}
|
}
|
||||||
const long double two_pi = 6.2831853071795864769252867665590057683943387987502116419498;
|
const long double two_pi = 6.2831853071795864769252867665590057683943387987502116419498;
|
||||||
double wi_denominator = log(r0 / radius) + skin_factor;
|
double wi_denominator = log(r0 / radius) + skin_factor;
|
||||||
double wi_numerator = two_pi * cubical[2];
|
double wi_numerator = two_pi * cubical[2];
|
||||||
assert(wi_denominator > 0.0);
|
assert(wi_denominator > 0.0);
|
||||||
double wi = effective_perm * wi_numerator / wi_denominator;
|
double wi = effective_perm * wi_numerator / wi_denominator;
|
||||||
assert(wi > 0.0);
|
assert(wi > 0.0);
|
||||||
return wi;
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -174,7 +185,7 @@ namespace Opm
|
|||||||
|
|
||||||
/// Default constructor.
|
/// Default constructor.
|
||||||
WellsManager::WellsManager()
|
WellsManager::WellsManager()
|
||||||
: w_(0)
|
: w_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,45 +193,48 @@ namespace Opm
|
|||||||
|
|
||||||
/// Construct wells from deck.
|
/// Construct wells from deck.
|
||||||
WellsManager::WellsManager(const Opm::EclipseGridParser& deck,
|
WellsManager::WellsManager(const Opm::EclipseGridParser& deck,
|
||||||
const UnstructuredGrid& grid,
|
const UnstructuredGrid& grid,
|
||||||
const double* permeability)
|
const double* permeability)
|
||||||
: w_(0)
|
: w_(0)
|
||||||
{
|
{
|
||||||
if (grid.dimensions != 3) {
|
if (grid.dimensions != 3) {
|
||||||
THROW("We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional.");
|
THROW("We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional.");
|
||||||
}
|
}
|
||||||
// NOTE: Implementation copied and modified from dune-porsol's class BlackoilWells.
|
// NOTE: Implementation copied and modified from dune-porsol's class BlackoilWells.
|
||||||
std::vector<std::string> keywords;
|
std::vector<std::string> keywords;
|
||||||
keywords.push_back("WELSPECS");
|
keywords.push_back("WELSPECS");
|
||||||
keywords.push_back("COMPDAT");
|
keywords.push_back("COMPDAT");
|
||||||
// keywords.push_back("WELTARG");
|
// keywords.push_back("WELTARG");
|
||||||
if (!deck.hasFields(keywords)) {
|
if (!deck.hasFields(keywords)) {
|
||||||
MESSAGE("Missing well keywords in deck, initializing no wells.");
|
MESSAGE("Missing well keywords in deck, initializing no wells.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(deck.hasField("WCONINJE") || deck.hasField("WCONPROD")) ) {
|
if (!(deck.hasField("WCONINJE") || deck.hasField("WCONPROD")) ) {
|
||||||
THROW("Needed field is missing in file");
|
THROW("Needed field is missing in file");
|
||||||
}
|
}
|
||||||
|
|
||||||
// These data structures will be filled in this constructor,
|
// Obtain phase usage data.
|
||||||
// then used to initialize the Wells struct.
|
PhaseUsage pu = phaseUsageFromDeck(deck);
|
||||||
std::vector<std::string> well_names;
|
|
||||||
|
// These data structures will be filled in this constructor,
|
||||||
|
// then used to initialize the Wells struct.
|
||||||
|
std::vector<std::string> well_names;
|
||||||
std::vector<WellData> well_data;
|
std::vector<WellData> well_data;
|
||||||
std::vector<std::vector<PerfData> > wellperf_data;
|
std::vector<std::vector<PerfData> > wellperf_data;
|
||||||
|
|
||||||
// For easy lookup:
|
// For easy lookup:
|
||||||
std::map<std::string, int> well_names_to_index;
|
std::map<std::string, int> well_names_to_index;
|
||||||
|
|
||||||
// Get WELSPECS data
|
// Get WELSPECS data
|
||||||
const WELSPECS& welspecs = deck.getWELSPECS();
|
const WELSPECS& welspecs = deck.getWELSPECS();
|
||||||
const int num_wells = welspecs.welspecs.size();
|
const int num_wells = welspecs.welspecs.size();
|
||||||
well_names.reserve(num_wells);
|
well_names.reserve(num_wells);
|
||||||
well_data.reserve(num_wells);
|
well_data.reserve(num_wells);
|
||||||
wellperf_data.resize(num_wells);
|
wellperf_data.resize(num_wells);
|
||||||
for (int w = 0; w < num_wells; ++w) {
|
for (int w = 0; w < num_wells; ++w) {
|
||||||
well_names.push_back(welspecs.welspecs[w].name_);
|
well_names.push_back(welspecs.welspecs[w].name_);
|
||||||
WellData wd;
|
WellData wd;
|
||||||
well_data.push_back(wd);
|
well_data.push_back(wd);
|
||||||
well_names_to_index[welspecs.welspecs[w].name_] = w;
|
well_names_to_index[welspecs.welspecs[w].name_] = w;
|
||||||
well_data.back().reference_bhp_depth = welspecs.welspecs[w].datum_depth_BHP_;
|
well_data.back().reference_bhp_depth = welspecs.welspecs[w].datum_depth_BHP_;
|
||||||
if (welspecs.welspecs[w].datum_depth_BHP_ < 0.0) {
|
if (welspecs.welspecs[w].datum_depth_BHP_ < 0.0) {
|
||||||
@ -228,41 +242,41 @@ namespace Opm
|
|||||||
// after getting perforation data to the centroid of
|
// after getting perforation data to the centroid of
|
||||||
// the cell of the top well perforation.
|
// the cell of the top well perforation.
|
||||||
well_data.back().reference_bhp_depth = -1e100;
|
well_data.back().reference_bhp_depth = -1e100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// global_cell is a map from compressed cells to Cartesian grid cells.
|
// global_cell is a map from compressed cells to Cartesian grid cells.
|
||||||
// We must make the inverse lookup.
|
// We must make the inverse lookup.
|
||||||
const int* global_cell = grid.global_cell;
|
const int* global_cell = grid.global_cell;
|
||||||
const int* cpgdim = grid.cartdims;
|
const int* cpgdim = grid.cartdims;
|
||||||
std::map<int,int> cartesian_to_compressed;
|
std::map<int,int> cartesian_to_compressed;
|
||||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get COMPDAT data
|
// Get COMPDAT data
|
||||||
const COMPDAT& compdat = deck.getCOMPDAT();
|
const COMPDAT& compdat = deck.getCOMPDAT();
|
||||||
const int num_compdat = compdat.compdat.size();
|
const int num_compdat = compdat.compdat.size();
|
||||||
for (int kw = 0; kw < num_compdat; ++kw) {
|
for (int kw = 0; kw < num_compdat; ++kw) {
|
||||||
// Extract well name, or the part of the well name that
|
// Extract well name, or the part of the well name that
|
||||||
// comes before the '*'.
|
// comes before the '*'.
|
||||||
std::string name = compdat.compdat[kw].well_;
|
std::string name = compdat.compdat[kw].well_;
|
||||||
std::string::size_type len = name.find('*');
|
std::string::size_type len = name.find('*');
|
||||||
if (len != std::string::npos) {
|
if (len != std::string::npos) {
|
||||||
name = name.substr(0, len);
|
name = name.substr(0, len);
|
||||||
}
|
}
|
||||||
// Look for well with matching name.
|
// Look for well with matching name.
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (int wix = 0; wix < num_wells; ++wix) {
|
for (int wix = 0; wix < num_wells; ++wix) {
|
||||||
if (well_names[wix].compare(0,len, name) == 0) { // equal
|
if (well_names[wix].compare(0,len, name) == 0) { // equal
|
||||||
// We have a matching name.
|
// We have a matching name.
|
||||||
int ix = compdat.compdat[kw].grid_ind_[0] - 1;
|
int ix = compdat.compdat[kw].grid_ind_[0] - 1;
|
||||||
int jy = compdat.compdat[kw].grid_ind_[1] - 1;
|
int jy = compdat.compdat[kw].grid_ind_[1] - 1;
|
||||||
int kz1 = compdat.compdat[kw].grid_ind_[2] - 1;
|
int kz1 = compdat.compdat[kw].grid_ind_[2] - 1;
|
||||||
int kz2 = compdat.compdat[kw].grid_ind_[3] - 1;
|
int kz2 = compdat.compdat[kw].grid_ind_[3] - 1;
|
||||||
for (int kz = kz1; kz <= kz2; ++kz) {
|
for (int kz = kz1; kz <= kz2; ++kz) {
|
||||||
int cart_grid_indx = ix + cpgdim[0]*(jy + cpgdim[1]*kz);
|
int cart_grid_indx = ix + cpgdim[0]*(jy + cpgdim[1]*kz);
|
||||||
std::map<int, int>::const_iterator cgit =
|
std::map<int, int>::const_iterator cgit =
|
||||||
cartesian_to_compressed.find(cart_grid_indx);
|
cartesian_to_compressed.find(cart_grid_indx);
|
||||||
if (cgit == cartesian_to_compressed.end()) {
|
if (cgit == cartesian_to_compressed.end()) {
|
||||||
THROW("Cell with i,j,k indices " << ix << ' ' << jy << ' '
|
THROW("Cell with i,j,k indices " << ix << ' ' << jy << ' '
|
||||||
@ -279,8 +293,8 @@ namespace Opm
|
|||||||
radius = 0.5*unit::feet;
|
radius = 0.5*unit::feet;
|
||||||
MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||||
}
|
}
|
||||||
std::tr1::array<double, 3> cubical = getCubeDim(grid, cell);
|
std::tr1::array<double, 3> cubical = getCubeDim(grid, cell);
|
||||||
const double* cell_perm = &permeability[grid.dimensions*grid.dimensions*cell];
|
const double* cell_perm = &permeability[grid.dimensions*grid.dimensions*cell];
|
||||||
pd.well_index = computeWellIndex(radius, cubical, cell_perm,
|
pd.well_index = computeWellIndex(radius, cubical, cell_perm,
|
||||||
compdat.compdat[kw].skin_factor_);
|
compdat.compdat[kw].skin_factor_);
|
||||||
}
|
}
|
||||||
@ -290,16 +304,17 @@ namespace Opm
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
THROW("Undefined well name: " << compdat.compdat[kw].well_
|
THROW("Undefined well name: " << compdat.compdat[kw].well_
|
||||||
<< " in COMPDAT");
|
<< " in COMPDAT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up reference depths that were defaulted. Count perfs.
|
// Set up reference depths that were defaulted. Count perfs.
|
||||||
int num_perfs = 0;
|
int num_perfs = 0;
|
||||||
|
ASSERT(grid.dimensions == 3);
|
||||||
for (int w = 0; w < num_wells; ++w) {
|
for (int w = 0; w < num_wells; ++w) {
|
||||||
num_perfs += wellperf_data[w].size();
|
num_perfs += wellperf_data[w].size();
|
||||||
if (well_data[w].reference_bhp_depth == -1e100) {
|
if (well_data[w].reference_bhp_depth == -1e100) {
|
||||||
// It was defaulted. Set reference depth to minimum perforation depth.
|
// It was defaulted. Set reference depth to minimum perforation depth.
|
||||||
double min_depth = 1e100;
|
double min_depth = 1e100;
|
||||||
@ -311,15 +326,38 @@ namespace Opm
|
|||||||
well_data[w].reference_bhp_depth = min_depth;
|
well_data[w].reference_bhp_depth = min_depth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get WCONINJE data
|
// Create the well data structures.
|
||||||
|
w_ = create_wells(pu.num_phases, num_wells, num_perfs);
|
||||||
|
if (!w_) {
|
||||||
|
THROW("Failed creating Wells struct.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add wells.
|
||||||
|
for (int w = 0; w < num_wells; ++w) {
|
||||||
|
const int w_num_perf = wellperf_data[w].size();
|
||||||
|
std::vector<int> perf_cells(w_num_perf);
|
||||||
|
std::vector<double> perf_prodind(w_num_perf);
|
||||||
|
for (int perf = 0; perf < w_num_perf; ++perf) {
|
||||||
|
perf_cells[0] = wellperf_data[w][perf].cell;
|
||||||
|
perf_prodind[0] = wellperf_data[w][perf].well_index;
|
||||||
|
}
|
||||||
|
const double* comp_frac = NULL;
|
||||||
|
// We initialize all wells with a null component fraction,
|
||||||
|
// and must (for injection wells) overwrite it later.
|
||||||
|
add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf,
|
||||||
|
comp_frac, &perf_cells[0], &perf_prodind[0], w_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get WCONINJE data, add injection controls to wells.
|
||||||
if (deck.hasField("WCONINJE")) {
|
if (deck.hasField("WCONINJE")) {
|
||||||
const WCONINJE& wconinjes = deck.getWCONINJE();
|
const WCONINJE& wconinjes = deck.getWCONINJE();
|
||||||
const int num_wconinjes = wconinjes.wconinje.size();
|
const int num_wconinjes = wconinjes.wconinje.size();
|
||||||
for (int kw = 0; kw < num_wconinjes; ++kw) {
|
for (int kw = 0; kw < num_wconinjes; ++kw) {
|
||||||
// Extract well name, or the part of the well name that
|
const WconinjeLine& wci_line = wconinjes.wconinje[kw];
|
||||||
// comes before the '*'.
|
// Extract well name, or the part of the well name that
|
||||||
std::string name = wconinjes.wconinje[kw].well_;
|
// comes before the '*'.
|
||||||
|
std::string name = wci_line.well_;
|
||||||
std::string::size_type len = name.find('*');
|
std::string::size_type len = name.find('*');
|
||||||
if (len != std::string::npos) {
|
if (len != std::string::npos) {
|
||||||
name = name.substr(0, len);
|
name = name.substr(0, len);
|
||||||
@ -328,118 +366,168 @@ namespace Opm
|
|||||||
for (int wix = 0; wix < num_wells; ++wix) {
|
for (int wix = 0; wix < num_wells; ++wix) {
|
||||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||||
well_found = true;
|
well_found = true;
|
||||||
well_data[wix].type = INJECTOR;
|
ASSERT(well_data[wix].type == w_->type[wix]);
|
||||||
int m = inje_control_mode(wconinjes.wconinje[kw].control_mode_);
|
if (well_data[wix].type != INJECTOR) {
|
||||||
switch(m) {
|
THROW("Found WCONINJE entry for a non-injector well: " << well_names[wix]);
|
||||||
case 0: // RATE
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconinjes.wconinje[kw].surface_flow_max_rate_;
|
|
||||||
break;
|
|
||||||
case 1: // RESV
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconinjes.wconinje[kw].fluid_volume_max_rate_;
|
|
||||||
break;
|
|
||||||
case 2: // BHP
|
|
||||||
well_data[wix].control = BHP;
|
|
||||||
well_data[wix].target = wconinjes.wconinje[kw].BHP_limit_;
|
|
||||||
break;
|
|
||||||
case 3: // THP
|
|
||||||
well_data[wix].control = BHP;
|
|
||||||
well_data[wix].target = wconinjes.wconinje[kw].THP_limit_;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
THROW("Unknown well control mode; WCONIJE = "
|
|
||||||
<< wconinjes.wconinje[kw].control_mode_
|
|
||||||
<< " in input file");
|
|
||||||
}
|
}
|
||||||
if (wconinjes.wconinje[kw].injector_type_ == "WATER") {
|
|
||||||
well_data[wix].injected_phase = WATER;
|
// Add all controls that are present in well.
|
||||||
} else if (wconinjes.wconinje[kw].injector_type_ == "OIL") {
|
int control_pos[5] = { -1, -1, -1, -1, -1 };
|
||||||
well_data[wix].injected_phase = OIL;
|
if (wci_line.surface_flow_max_rate_ > 0.0) {
|
||||||
} else if (wconinjes.wconinje[kw].injector_type_ == "GAS") {
|
control_pos[InjectionControl::RATE] = w_->ctrls[wix]->num;
|
||||||
well_data[wix].injected_phase = GAS;
|
const double distr[3] = { 1.0, 1.0, 1.0 };
|
||||||
} else {
|
append_well_controls(SURFACE_RATE, wci_line.surface_flow_max_rate_,
|
||||||
THROW("Error in injector specification, found no known fluid type.");
|
distr, wix, w_);
|
||||||
}
|
}
|
||||||
}
|
if (wci_line.reservoir_flow_max_rate_ > 0.0) {
|
||||||
}
|
control_pos[InjectionControl::RESV] = w_->ctrls[wix]->num;
|
||||||
|
const double distr[3] = { 1.0, 1.0, 1.0 };
|
||||||
|
append_well_controls(RESERVOIR_RATE, wci_line.reservoir_flow_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wci_line.BHP_limit_ > 0.0) {
|
||||||
|
control_pos[InjectionControl::BHP] = w_->ctrls[wix]->num;
|
||||||
|
append_well_controls(BHP, wci_line.BHP_limit_,
|
||||||
|
NULL, wix, w_);
|
||||||
|
}
|
||||||
|
if (wci_line.THP_limit_ > 0.0) {
|
||||||
|
THROW("We cannot handle THP limit for well " << well_names[wix]);
|
||||||
|
}
|
||||||
|
InjectionControl::Mode mode = InjectionControl::mode(wci_line.control_mode_);
|
||||||
|
const int cpos = control_pos[mode];
|
||||||
|
if (cpos == -1 && mode != InjectionControl::GRUP) {
|
||||||
|
THROW("Control mode type " << mode << " not present in well " << well_names[wix]);
|
||||||
|
}
|
||||||
|
set_current_control(wix, cpos, w_);
|
||||||
|
|
||||||
|
// Set well component fraction.
|
||||||
|
double cf[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
if (wci_line.injector_type_ == "WATER") {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||||
|
THROW("Water phase not used, yet found water-injecting well.");
|
||||||
|
}
|
||||||
|
cf[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||||
|
} else if (wci_line.injector_type_ == "OIL") {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||||
|
THROW("Oil phase not used, yet found oil-injecting well.");
|
||||||
|
}
|
||||||
|
cf[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
|
} else if (wci_line.injector_type_ == "GAS") {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||||
|
THROW("Water phase not used, yet found water-injecting well.");
|
||||||
|
}
|
||||||
|
cf[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||||
|
}
|
||||||
|
std::copy(cf, cf + pu.num_phases, w_->comp_frac + wix*pu.num_phases);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!well_found) {
|
if (!well_found) {
|
||||||
THROW("Undefined well name: " << wconinjes.wconinje[kw].well_
|
THROW("Undefined well name: " << wci_line.well_
|
||||||
<< " in WCONINJE");
|
<< " in WCONINJE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get WCONPROD data
|
// Get WCONPROD data
|
||||||
if (deck.hasField("WCONPROD")) {
|
if (deck.hasField("WCONPROD")) {
|
||||||
const WCONPROD& wconprods = deck.getWCONPROD();
|
const WCONPROD& wconprods = deck.getWCONPROD();
|
||||||
const int num_wconprods = wconprods.wconprod.size();
|
const int num_wconprods = wconprods.wconprod.size();
|
||||||
std::cout << "num_wconprods = " <<num_wconprods << std::endl;
|
|
||||||
for (int kw = 0; kw < num_wconprods; ++kw) {
|
for (int kw = 0; kw < num_wconprods; ++kw) {
|
||||||
std::string name = wconprods.wconprod[kw].well_;
|
const WconprodLine& wcp_line = wconprods.wconprod[kw];
|
||||||
|
std::string name = wcp_line.well_;
|
||||||
std::string::size_type len = name.find('*');
|
std::string::size_type len = name.find('*');
|
||||||
if (len != std::string::npos) {
|
if (len != std::string::npos) {
|
||||||
name = name.substr(0, len);
|
name = name.substr(0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool well_found = false;
|
bool well_found = false;
|
||||||
for (int wix = 0; wix < num_wells; ++wix) {
|
for (int wix = 0; wix < num_wells; ++wix) {
|
||||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||||
well_found = true;
|
well_found = true;
|
||||||
well_data[wix].type = PRODUCER;
|
ASSERT(well_data[wix].type == w_->type[wix]);
|
||||||
int m = prod_control_mode(wconprods.wconprod[kw].control_mode_);
|
if (well_data[wix].type != PRODUCER) {
|
||||||
switch(m) {
|
THROW("Found WCONPROD entry for a non-producer well: " << well_names[wix]);
|
||||||
case 0: // ORAT
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].oil_max_rate_;
|
|
||||||
break;
|
|
||||||
case 1: // WRAT
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].water_max_rate_;
|
|
||||||
break;
|
|
||||||
case 2: // GRAT
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].gas_max_rate_;
|
|
||||||
break;
|
|
||||||
case 3: // LRAT
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].liquid_max_rate_;
|
|
||||||
break;
|
|
||||||
case 4: // RESV
|
|
||||||
well_data[wix].control = RATE;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].fluid_volume_max_rate_;
|
|
||||||
break;
|
|
||||||
case 5: // BHP
|
|
||||||
well_data[wix].control = BHP;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].BHP_limit_;
|
|
||||||
break;
|
|
||||||
case 6: // THP
|
|
||||||
well_data[wix].control = BHP;
|
|
||||||
well_data[wix].target = wconprods.wconprod[kw].THP_limit_;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
// Handle group here.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
THROW("Unknown well control mode; WCONPROD = "
|
|
||||||
<< wconprods.wconprod[kw].control_mode_
|
|
||||||
<< " in input file");
|
|
||||||
}
|
}
|
||||||
|
// Add all controls that are present in well.
|
||||||
|
int control_pos[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||||
|
if (wcp_line.oil_max_rate_ > 0.0) {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||||
|
THROW("Oil phase not active and ORAT control specified.");
|
||||||
|
}
|
||||||
|
control_pos[ProductionControl::ORAT] = w_->ctrls[wix]->num;
|
||||||
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
|
append_well_controls(SURFACE_RATE, wcp_line.oil_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.water_max_rate_ > 0.0) {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||||
|
THROW("Water phase not active and WRAT control specified.");
|
||||||
|
}
|
||||||
|
control_pos[ProductionControl::WRAT] = w_->ctrls[wix]->num;
|
||||||
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||||
|
append_well_controls(SURFACE_RATE, wcp_line.water_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.gas_max_rate_ > 0.0) {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||||
|
THROW("Gas phase not active and GRAT control specified.");
|
||||||
|
}
|
||||||
|
control_pos[ProductionControl::GRAT] = w_->ctrls[wix]->num;
|
||||||
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||||
|
append_well_controls(SURFACE_RATE, wcp_line.gas_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.liquid_max_rate_ > 0.0) {
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||||
|
THROW("Water phase not active and LRAT control specified.");
|
||||||
|
}
|
||||||
|
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||||
|
THROW("Oil phase not active and LRAT control specified.");
|
||||||
|
}
|
||||||
|
control_pos[ProductionControl::LRAT] = w_->ctrls[wix]->num;
|
||||||
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
|
append_well_controls(SURFACE_RATE, wcp_line.liquid_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.reservoir_flow_max_rate_ > 0.0) {
|
||||||
|
control_pos[ProductionControl::RESV] = w_->ctrls[wix]->num;
|
||||||
|
double distr[3] = { 1.0, 1.0, 1.0 };
|
||||||
|
append_well_controls(RESERVOIR_RATE, wcp_line.reservoir_flow_max_rate_,
|
||||||
|
distr, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.BHP_limit_ > 0.0) {
|
||||||
|
control_pos[ProductionControl::BHP] = w_->ctrls[wix]->num;
|
||||||
|
append_well_controls(BHP, wcp_line.BHP_limit_,
|
||||||
|
NULL, wix, w_);
|
||||||
|
}
|
||||||
|
if (wcp_line.THP_limit_ > 0.0) {
|
||||||
|
THROW("We cannot handle THP limit for well " << well_names[wix]);
|
||||||
|
}
|
||||||
|
ProductionControl::Mode mode = ProductionControl::mode(wcp_line.control_mode_);
|
||||||
|
const int cpos = control_pos[mode];
|
||||||
|
if (cpos == -1 && mode != ProductionControl::GRUP) {
|
||||||
|
THROW("Control mode type " << mode << " not present in well " << well_names[wix]);
|
||||||
|
}
|
||||||
|
set_current_control(wix, cpos, w_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!well_found) {
|
if (!well_found) {
|
||||||
THROW("Undefined well name: " << wconprods.wconprod[kw].well_
|
THROW("Undefined well name: " << wcp_line.well_
|
||||||
<< " in WCONPROD");
|
<< " in WCONPROD");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get WELTARG data
|
// Get WELTARG data
|
||||||
if (deck.hasField("WELTARG")) {
|
if (deck.hasField("WELTARG")) {
|
||||||
|
THROW("We currently do not handle WELTARG.");
|
||||||
|
/*
|
||||||
const WELTARG& weltargs = deck.getWELTARG();
|
const WELTARG& weltargs = deck.getWELTARG();
|
||||||
const int num_weltargs = weltargs.weltarg.size();
|
const int num_weltargs = weltargs.weltarg.size();
|
||||||
for (int kw = 0; kw < num_weltargs; ++kw) {
|
for (int kw = 0; kw < num_weltargs; ++kw) {
|
||||||
std::string name = weltargs.weltarg[kw].well_;
|
std::string name = weltargs.weltarg[kw].well_;
|
||||||
std::string::size_type len = name.find('*');
|
std::string::size_type len = name.find('*');
|
||||||
@ -459,43 +547,45 @@ namespace Opm
|
|||||||
<< " in WELTARG");
|
<< " in WELTARG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug output.
|
// Debug output.
|
||||||
#define EXTRA_OUTPUT
|
#define EXTRA_OUTPUT
|
||||||
#ifdef EXTRA_OUTPUT
|
#ifdef EXTRA_OUTPUT
|
||||||
std::cout << "\t WELL DATA" << std::endl;
|
/*
|
||||||
for(int i = 0; i< num_wells; ++i) {
|
std::cout << "\t WELL DATA" << std::endl;
|
||||||
std::cout << i << ": " << well_data[i].type << " "
|
for(int i = 0; i< num_wells; ++i) {
|
||||||
<< well_data[i].control << " " << well_data[i].target
|
std::cout << i << ": " << well_data[i].type << " "
|
||||||
<< std::endl;
|
<< well_data[i].control << " " << well_data[i].target
|
||||||
}
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "\n\t PERF DATA" << std::endl;
|
std::cout << "\n\t PERF DATA" << std::endl;
|
||||||
for(int i=0; i< int(wellperf_data.size()); ++i) {
|
for(int i=0; i< int(wellperf_data.size()); ++i) {
|
||||||
for(int j=0; j< int(wellperf_data[i].size()); ++j) {
|
for(int j=0; j< int(wellperf_data[i].size()); ++j) {
|
||||||
std::cout << i << ": " << wellperf_data[i][j].cell << " "
|
std::cout << i << ": " << wellperf_data[i][j].cell << " "
|
||||||
<< wellperf_data[i][j].well_index << std::endl;
|
<< wellperf_data[i][j].well_index << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (deck.hasField("GRUPTREE")) {
|
// Build the well_collection_ well group hierarchy.
|
||||||
|
if (deck.hasField("GRUPTREE")) {
|
||||||
std::cout << "Found gruptree" << std::endl;
|
std::cout << "Found gruptree" << std::endl;
|
||||||
const GRUPTREE& gruptree = deck.getGRUPTREE();
|
const GRUPTREE& gruptree = deck.getGRUPTREE();
|
||||||
|
|
||||||
std::map<std::string, std::string>::const_iterator it = gruptree.tree.begin();
|
std::map<std::string, std::string>::const_iterator it = gruptree.tree.begin();
|
||||||
for( ; it != gruptree.tree.end(); ++it) {
|
for( ; it != gruptree.tree.end(); ++it) {
|
||||||
well_collection_.addChild(it->first, it->second, deck);
|
well_collection_.addChild(it->first, it->second, deck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < welspecs.welspecs.size(); ++i) {
|
for (size_t i = 0; i < welspecs.welspecs.size(); ++i) {
|
||||||
WelspecsLine line = welspecs.welspecs[i];
|
WelspecsLine line = welspecs.welspecs[i];
|
||||||
well_collection_.addChild(line.name_, line.group_, deck);
|
well_collection_.addChild(line.name_, line.group_, deck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set the guide rates:
|
// Set the guide rates:
|
||||||
@ -506,110 +596,92 @@ namespace Opm
|
|||||||
std::cout << well_collection_.getLeafNodes().size() << std::endl;
|
std::cout << well_collection_.getLeafNodes().size() << std::endl;
|
||||||
for (size_t i = 0; i < lines.size(); i++) {
|
for (size_t i = 0; i < lines.size(); i++) {
|
||||||
std::string name = lines[i].well_;
|
std::string name = lines[i].well_;
|
||||||
int index = well_names_to_index[name];
|
const int wix = well_names_to_index[name];
|
||||||
ASSERT(well_collection_.getLeafNodes()[index]->name() == name);
|
WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
|
||||||
well_collection_.getLeafNodes()[index]->prodSpec().guide_rate_ = lines[i].guide_rate_;
|
ASSERT(wellnode.name() == name);
|
||||||
well_collection_.getLeafNodes()[index]->prodSpec().guide_rate_type_
|
if (well_data[wix].type == PRODUCER) {
|
||||||
= lines[i].phase_ == "OIL" ? ProductionSpecification::OIL : ProductionSpecification::RAT;
|
wellnode.prodSpec().guide_rate_ = lines[i].guide_rate_;
|
||||||
|
if (lines[i].phase_ == "OIL") {
|
||||||
|
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
|
||||||
|
} else {
|
||||||
|
THROW("Guide rate type " << lines[i].phase_ << " specified for producer "
|
||||||
|
<< name << " in WGRUPCON, cannot handle.");
|
||||||
|
}
|
||||||
|
} else if (well_data[wix].type == INJECTOR) {
|
||||||
|
wellnode.injSpec().guide_rate_ = lines[i].guide_rate_;
|
||||||
|
if (lines[i].phase_ == "RAT") {
|
||||||
|
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
|
||||||
|
} else {
|
||||||
|
THROW("Guide rate type " << lines[i].phase_ << " specified for injector "
|
||||||
|
<< name << " in WGRUPCON, cannot handle.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
THROW("Unknown well type " << well_data[wix].type << " for well " << name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
well_collection_.calculateGuideRates();
|
well_collection_.calculateGuideRates();
|
||||||
|
|
||||||
// Apply guide rates:
|
// Apply guide rates:
|
||||||
for (size_t i = 0; i < well_data.size(); i++) {
|
for (size_t wix = 0; wix < well_data.size(); wix++) {
|
||||||
if (well_data[i].type == PRODUCER && (well_collection_.getLeafNodes()[i]->prodSpec().control_mode_ == ProductionSpecification::GRUP)) {
|
const WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
|
||||||
switch (well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_type_ ) {
|
if (well_data[wix].type == PRODUCER && (wellnode.prodSpec().control_mode_ == ProductionSpecification::GRUP)) {
|
||||||
|
ASSERT(w_->ctrls[wix]->current == -1);
|
||||||
|
switch (wellnode.prodSpec().guide_rate_type_ ) {
|
||||||
case ProductionSpecification::OIL:
|
case ProductionSpecification::OIL:
|
||||||
{
|
{
|
||||||
const ProductionSpecification& parent_prod_spec =
|
const ProductionSpecification& parent_prod_spec =
|
||||||
well_collection_.getLeafNodes()[i]->getParent()->prodSpec();
|
wellnode.getParent()->prodSpec();
|
||||||
double guide_rate = well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_;
|
const double guide_rate = wellnode.prodSpec().guide_rate_;
|
||||||
well_data[i].target = guide_rate*parent_prod_spec.oil_max_rate_;
|
const double oil_target = guide_rate * parent_prod_spec.oil_max_rate_;
|
||||||
well_data[i].control = RATE;
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
well_data[i].type = PRODUCER;
|
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
std::cout << "WARNING: Converting oil control to rate control!" << std::endl;
|
const int control_index = w_->ctrls[wix]->num;
|
||||||
break;
|
append_well_controls(SURFACE_RATE, oil_target, distr, wix, w_);
|
||||||
|
set_current_control(wix, control_index, w_);
|
||||||
}
|
}
|
||||||
case ProductionSpecification::NONE_GRT:
|
case ProductionSpecification::NONE_GRT:
|
||||||
{
|
{
|
||||||
// Will use the group control type:
|
// Will use the group control type:
|
||||||
const ProductionSpecification& parent_prod_spec =
|
const ProductionSpecification& parent_prod_spec =
|
||||||
well_collection_.getLeafNodes()[i]->getParent()->prodSpec();
|
wellnode.getParent()->prodSpec();
|
||||||
double guide_rate = well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_;
|
const double guide_rate = wellnode.prodSpec().guide_rate_;
|
||||||
switch(parent_prod_spec.control_mode_) {
|
switch(parent_prod_spec.control_mode_) {
|
||||||
case ProductionSpecification::LRAT:
|
case ProductionSpecification::LRAT:
|
||||||
well_data[i].target = guide_rate * parent_prod_spec.liquid_max_rate_;
|
{
|
||||||
well_data[i].control = RATE;
|
const double liq_target = guide_rate * parent_prod_spec.liquid_max_rate_;
|
||||||
break;
|
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||||
|
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||||
|
append_well_controls(SURFACE_RATE, liq_target, distr, wix, w_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
THROW("Unhandled production specification control mode " << parent_prod_spec.control_mode_);
|
THROW("Unhandled parent production specification control mode " << parent_prod_spec.control_mode_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
THROW("Unhandled production specification guide rate type "
|
THROW("Unhandled production specification guide rate type "
|
||||||
<< well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_type_);
|
<< wellnode.prodSpec().guide_rate_type_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (well_data[i].type == INJECTOR && (well_collection_.getLeafNodes()[i]->injSpec().control_mode_ == InjectionSpecification::GRUP)) {
|
if (well_data[wix].type == INJECTOR && (wellnode.injSpec().control_mode_ == InjectionSpecification::GRUP)) {
|
||||||
if (well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_type_ == ProductionSpecification::RAT) {
|
ASSERT(w_->ctrls[wix]->current == -1);
|
||||||
well_data[i].injected_phase = WATER; // Default for now.
|
if (wellnode.injSpec().guide_rate_type_ == InjectionSpecification::RAT) {
|
||||||
well_data[i].control = RATE;
|
const double parent_surface_rate = wellnode.getParent()->injSpec().surface_flow_max_rate_;
|
||||||
well_data[i].type = INJECTOR;
|
const double guide_rate = wellnode.prodSpec().guide_rate_;
|
||||||
double parent_surface_rate = well_collection_.getLeafNodes()[i]->getParent()->injSpec().surface_flow_max_rate_;
|
const double target = guide_rate * parent_surface_rate;
|
||||||
double guide_rate = well_collection_.getLeafNodes()[i]->prodSpec().guide_rate_;
|
const double distr[3] = { 1.0, 1.0, 1.0 };
|
||||||
well_data[i].target = guide_rate * parent_surface_rate;
|
append_well_controls(SURFACE_RATE, target, distr, wix, w_);
|
||||||
std::cout << "Applying guide rate" << std::endl;
|
} else {
|
||||||
|
THROW("Unhandled injection specification guide rate type "
|
||||||
|
<< wellnode.injSpec().guide_rate_type_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::cout << "Making well structs" << std::endl;
|
|
||||||
// Set up the Wells struct.
|
|
||||||
w_ = create_wells(num_wells, num_perfs);
|
|
||||||
if (!w_) {
|
|
||||||
THROW("Failed creating Wells struct.");
|
|
||||||
}
|
|
||||||
double fracs[3][3] = { { 1.0, 0.0, 0.0 },
|
|
||||||
{ 0.0, 1.0, 0.0 },
|
|
||||||
{ 0.0, 0.0, 1.0 } };
|
|
||||||
for (int w = 0; w < num_wells; ++w) {
|
|
||||||
int nperf = wellperf_data[w].size();
|
|
||||||
std::vector<int> cells(nperf);
|
|
||||||
std::vector<double> wi(nperf);
|
|
||||||
for (int perf = 0; perf < nperf; ++perf) {
|
|
||||||
cells[perf] = wellperf_data[w][perf].cell;
|
|
||||||
wi[perf] = wellperf_data[w][perf].well_index;
|
|
||||||
}
|
|
||||||
const double* zfrac = (well_data[w].type == INJECTOR) ? fracs[well_data[w].injected_phase] : 0;
|
|
||||||
|
|
||||||
// DIRTY DIRTY HACK to temporarily make things work in spite of bugs in the deck reader.
|
|
||||||
if(well_data[w].type == INJECTOR && (well_data[w].injected_phase < 0 || well_data[w].injected_phase > 2)){
|
|
||||||
zfrac = fracs[WATER];
|
|
||||||
}
|
|
||||||
|
|
||||||
int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, nperf,
|
|
||||||
zfrac, &cells[0], &wi[0], w_);
|
|
||||||
if (!ok) {
|
|
||||||
THROW("Failed to add a well.");
|
|
||||||
}
|
|
||||||
// We only append a single control at this point.
|
|
||||||
// TODO: Handle multiple controls.
|
|
||||||
if (well_data[w].type == PRODUCER && well_data[w].control == RATE) {
|
|
||||||
// Convention is that well rates for producers are negative.
|
|
||||||
well_data[w].target = -well_data[w].target;
|
|
||||||
}
|
|
||||||
ok = append_well_controls(well_data[w].control, well_data[w].target, w_->ctrls[w]);
|
|
||||||
w_->ctrls[w]->current = 0;
|
|
||||||
if (!ok) {
|
|
||||||
THROW("Failed to add well controls.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Made well struct" << std::endl;
|
|
||||||
well_collection_.setWellsPointer(w_);
|
well_collection_.setWellsPointer(w_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +690,7 @@ namespace Opm
|
|||||||
/// Destructor.
|
/// Destructor.
|
||||||
WellsManager::~WellsManager()
|
WellsManager::~WellsManager()
|
||||||
{
|
{
|
||||||
destroy_wells(w_);
|
destroy_wells(w_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -629,7 +701,7 @@ namespace Opm
|
|||||||
/// to make it clear that we are returning a C-compatible struct.
|
/// to make it clear that we are returning a C-compatible struct.
|
||||||
const Wells* WellsManager::c_wells() const
|
const Wells* WellsManager::c_wells() const
|
||||||
{
|
{
|
||||||
return w_;
|
return w_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WellCollection& WellsManager::wellCollection() const
|
const WellCollection& WellsManager::wellCollection() const
|
||||||
@ -637,8 +709,8 @@ namespace Opm
|
|||||||
return well_collection_;
|
return well_collection_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
|
bool WellsManager::conditionsMet(const std::vector<double>& well_bhp,
|
||||||
const std::vector<double>& well_rate)
|
const std::vector<double>& well_rate)
|
||||||
{
|
{
|
||||||
return well_collection_.conditionsMet(well_bhp, well_rate);
|
return well_collection_.conditionsMet(well_bhp, well_rate);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user