Significant modification of well data structures and related functions.

The following changes are made:
 - The SurfaceComponent enum has been removed.
 - Added new member Wells::number_of_phases.
 - The Wells::zfrac member has been replaced with comp_frac. The old
   zfrac always had 3 components per well (accessed according to the
   canonical ordering given by SurfaceComponent), the new one has
   number_of_phases components per well.
 - Changed add_well() accordingly to accept comp_frac.
 - Added new member WellControls::distr, giving distributions for
   rate controls.
 - All functions dealing with well controls now take Wells* and a
   well index instead of directly taking WellControls*.
 - Now append_well_controls() also takes a rate distribution argument.
 - Added new public function set_current_control().
This commit is contained in:
Atgeirr Flø Rasmussen 2012-04-26 13:55:35 +02:00
parent 743085bd16
commit 597a2cc7af
2 changed files with 119 additions and 66 deletions

View File

@ -35,26 +35,29 @@ extern "C" {
/** Well type indicates desired/expected well behaviour. */
enum WellType { INJECTOR, PRODUCER };
/** Type of well control equation or inequality constraint.
* BHP -> Well constrained by bottom-hole pressure target.
* RATE -> Well constrained by total reservoir volume flow rate.
*/
enum WellControlType { BHP , RATE };
/** Canonical component names and ordering. */
enum SurfaceComponent { WATER = 0, OIL = 1, GAS = 2 };
/** Type of well control equation or inequality constraint.
* BHP -> Well constrained by bottom-hole pressure target.
* RESERVOIR_RATE -> Well constrained by reservoir volume flow rates.
* SURFACE_RATE -> Well constrained by surface volume flow rates.
*/
enum WellControlType { BHP, RESERVOIR_RATE, SURFACE_RATE };
/** Controls for a single well.
* Each control specifies a well rate or bottom-hole pressure. Only
* one control can be active at a time, indicated by current. The
* meaning of each control's target value depends on the control
* type, for BHP controls it is a pressure in Pascal, for RATE
* controls it is a volumetric rate in cubic(meter)/second. The sign
* convention for RATE targets is as follows:
* meaning of each control's target value depends on the control type:
* BHP -> target pressure in Pascal.
* RESERVOIR_RATE -> target reservoir volume rate in cubic(meter)/second
* SURFACE_RATE -> target surface volume rate in cubic(meter)/second
* The sign convention for RATE targets is as follows:
* (+) Fluid flowing into reservoir, i.e. injecting.
* (-) Fluid flowing out of reservoir, i.e. producing.
* The active control as an equality constraint, whereas the
* For *_RATE controls, the distribution of phases used for the control
* is also needed. For example, a total rate control should have 1.0
* for each phase, whereas a control on oil rate should have 1.0 for
* the oil phase and 0.0 for the rest. For BHP controls, this is unused.
* The active control acts as an equality constraint, whereas the
* non-active controls should be interpreted as inequality
* constraints (upper or lower bounds). For instance, a PRODUCER's
* BHP constraint defines a minimum acceptable bottom-hole pressure
@ -63,8 +66,10 @@ enum SurfaceComponent { WATER = 0, OIL = 1, GAS = 2 };
struct WellControls
{
int num; /** Number of controls. */
enum WellControlType *type; /** Array of control types. */
double *target; /** Array of control targets. */
enum WellControlType *type; /** Array of control types.*/
double *target; /** Array of control targets */
double *distr; /** Array of rate control distributions,
Wells::number_of_phases numbers per well */
int current; /** Index of current active control. */
void *data; /** Internal management structure. */
@ -75,19 +80,20 @@ struct WellControls
/** Data structure aggregating static information about all wells in a scenario. */
struct Wells
{
int number_of_wells; /** Number of wells. */
int number_of_wells; /** Number of wells. */
int number_of_phases; /** Number of phases. */
enum WellType *type; /** Array of well types. */
double *depth_ref; /** Array of well bhp reference depths. */
double *zfrac; /** Component volume fractions for each well, size is (3*number_of_wells).
double *comp_frac; /** Component fractions for each well, size is (number_of_wells*number_of_phases).
* This is intended to be used for injection wells. For production wells
* the component fractions will vary and cannot be specified a priori.
*/
int *well_connpos; /** Array of indices into well_cells (and WI).
* For a well w, well_connpos[w] and well_connpos[w+1] yield
* start and one-beyond-end indices into the well_cells array
* for accessing w's perforation cell indices.
*/
* For a well w, well_connpos[w] and well_connpos[w+1] yield
* start and one-beyond-end indices into the well_cells array
* for accessing w's perforation cell indices.
*/
int *well_cells; /** Array of perforation cell indices.
* Size is number of perforations (== well_connpos[number_of_wells]).
*/
@ -130,19 +136,21 @@ struct CompletionData
* destroy_wells() to dispose of the Wells object and its allocated
* memory resources.
*
* \param[in] nwells Expected number of wells in simulation scenario.
* Pass zero if the total number of wells is unknown.
* \param[in] nphases Number of active phases in simulation scenario.
*
* \param[in] nperf Expected total number of well connections
* (perforations) for all wells in simulation
* scenario. Pass zero if the total number of well
* connections is unknown.
* \param[in] nwells Expected number of wells in simulation scenario.
* Pass zero if the total number of wells is unknown.
*
* \param[in] nperf Expected total number of well connections
* (perforations) for all wells in simulation
* scenario. Pass zero if the total number of well
* connections is unknown.
*
* \return A valid Wells object with no wells if successful, and NULL
* otherwise.
*/
struct Wells *
create_wells(int nwells, int nperf);
create_wells(int nphases, int nwells, int nperf);
/**
@ -156,7 +164,7 @@ create_wells(int nwells, int nperf);
* \param[in] type Type of well.
* \param[in] depth_ref Reference depth for well's BHP.
* \param[in] nperf Number of perforations.
* \param[in] zfrac Injection fraction (three components) or NULL.
* \param[in] comp_frac Injection fraction array (size equal to W->number_of_phases) or NULL.
* \param[in] cells Grid cells in which well is perforated. Should
* ideally be track ordered.
* \param[in] WI Well production index per perforation, or NULL.
@ -169,7 +177,7 @@ int
add_well(enum WellType type ,
double depth_ref,
int nperf ,
const double *zfrac ,
const double *comp_frac,
const int *cells ,
const double *WI ,
struct Wells *W );
@ -181,23 +189,35 @@ add_well(enum WellType type ,
* Increments ctrl->num by one if successful. Introducing a new
* operational constraint does not affect the well's notion of the
* currently active constraint represented by ctrl->current.
* Note that *_RATE controls now require a phase distribution array
* to be associated with the control, see WellControls.
*
* \param[in] type Control type.
* \param[in] target Target value for the control.
* \param[inout] ctrl Existing set of well controls.
* \param[in] type Control type.
* \param[in] target Target value for the control.
* \param[in] distr Array of size W->number_of_phases or NULL.
* \param[in] well_index Index of well to receive additional control.
* \param[in,out] W Existing set of well controls.
* \return Non-zero (true) if successful and zero (false) otherwise.
*/
int
append_well_controls(enum WellControlType type ,
double target,
struct WellControls *ctrl );
const double *distr,
int well_index,
struct Wells *W);
/**
* Clear all controls from a well.
* Set the current control for a single well.
*/
void
set_current_control(int well_index, int current_control, struct Wells *W);
/**
* Clear all controls from a single well.
*
* Does not affect the control set capacity. */
void
clear_well_controls(struct WellControls *ctrl);
clear_well_controls(int well_index, struct Wells *W);
/**

View File

@ -103,6 +103,7 @@ well_controls_destroy(struct WellControls *ctrl)
{
if (ctrl != NULL) {
destroy_ctrl_mgmt(ctrl->data);
free (ctrl->distr);
free (ctrl->target);
free (ctrl->type);
}
@ -125,6 +126,7 @@ well_controls_create(void)
ctrl->num = 0;
ctrl->type = NULL;
ctrl->target = NULL;
ctrl->distr = NULL;
ctrl->current = -1;
ctrl->data = create_ctrl_mgmt();
@ -141,26 +143,31 @@ well_controls_create(void)
/* ---------------------------------------------------------------------- */
static int
well_controls_reserve(int nctrl, struct WellControls *ctrl)
well_controls_reserve(int nctrl, int nphases, struct WellControls *ctrl)
/* ---------------------------------------------------------------------- */
{
int c, ok;
void *type, *target;
int c, p, ok;
void *type, *target, *distr;
struct WellControlMgmt *m;
type = realloc(ctrl->type , nctrl * sizeof *ctrl->type );
target = realloc(ctrl->target, nctrl * sizeof *ctrl->target);
distr = realloc(ctrl->distr , nphases * nctrl * sizeof *ctrl->distr );
ok = 0;
if (type != NULL) { ctrl->type = type ; ok++; }
if (target != NULL) { ctrl->target = target; ok++; }
if (distr != NULL) { ctrl->distr = distr ; ok++; }
if (ok == 2) {
m = ctrl->data;
for (c = m->cpty; c < nctrl; c++) {
ctrl->type [c] = BHP;
ctrl->target[c] = -1.0;
for (p = 0; p < nphases; ++p) {
ctrl->distr [nphases*c + p] = 0.0;
}
}
m->cpty = nctrl;
@ -175,15 +182,17 @@ static int
wells_allocate(int nwells, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok;
void *type, *depth_ref, *zfrac;
int ok, np;
void *type, *depth_ref, *comp_frac;
void *well_connpos;
void *ctrls;
type = realloc(W->type , 1 * nwells * sizeof *W->type);
depth_ref = realloc(W->depth_ref, 1 * nwells * sizeof *W->depth_ref);
zfrac = realloc(W->zfrac , 3 * nwells * sizeof *W->zfrac);
ctrls = realloc(W->ctrls , 1 * nwells * sizeof *W->ctrls);
np = W->number_of_phases;
type = realloc(W->type , 1 * nwells * sizeof *W->type);
depth_ref = realloc(W->depth_ref, 1 * nwells * sizeof *W->depth_ref);
comp_frac = realloc(W->comp_frac, np * nwells * sizeof *W->comp_frac);
ctrls = realloc(W->ctrls , 1 * nwells * sizeof *W->ctrls);
well_connpos = realloc(W->well_connpos,
(nwells + 1) * sizeof *W->well_connpos);
@ -191,7 +200,7 @@ wells_allocate(int nwells, struct Wells *W)
ok = 0;
if (type != NULL) { W->type = type ; ok++; }
if (depth_ref != NULL) { W->depth_ref = depth_ref ; ok++; }
if (zfrac != NULL) { W->zfrac = zfrac ; ok++; }
if (comp_frac != NULL) { W->comp_frac = comp_frac ; ok++; }
if (well_connpos != NULL) { W->well_connpos = well_connpos; ok++; }
if (ctrls != NULL) { W->ctrls = ctrls ; ok++; }
@ -223,7 +232,7 @@ static int
initialise_new_wells(int nwells, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok, w;
int ok, w, p;
struct WellMgmt *m;
@ -233,9 +242,9 @@ initialise_new_wells(int nwells, struct Wells *W)
W->type [w] = PRODUCER;
W->depth_ref[w] = -1.0;
W->zfrac[3*w + WATER] = 0.0;
W->zfrac[3*w + OIL ] = 0.0;
W->zfrac[3*w + GAS ] = 0.0;
for (p = 0; p < W->number_of_phases; ++p) {
W->comp_frac[W->number_of_phases*w + p] = 0.0;
}
W->well_connpos[w + 1] = W->well_connpos[w];
}
@ -322,7 +331,7 @@ wells_reserve(int nwells, int nperf, struct Wells *W)
/* ---------------------------------------------------------------------- */
struct Wells *
create_wells(int nwells, int nperf)
create_wells(int nphases, int nwells, int nperf)
/* ---------------------------------------------------------------------- */
{
int ok;
@ -332,10 +341,11 @@ create_wells(int nwells, int nperf)
if (W != NULL) {
W->number_of_wells = 0;
W->number_of_phases = nphases;
W->type = NULL;
W->depth_ref = NULL;
W->zfrac = NULL;
W->comp_frac = NULL;
W->well_connpos = malloc(1 * sizeof *W->well_connpos);
W->well_cells = NULL;
@ -386,7 +396,7 @@ destroy_wells(struct Wells *W)
free(W->WI);
free(W->well_cells);
free(W->well_connpos);
free(W->zfrac);
free(W->comp_frac);
free(W->depth_ref);
free(W->type);
}
@ -417,13 +427,13 @@ int
add_well(enum WellType type ,
double depth_ref,
int nperf ,
const double *zfrac , /* Injection fraction or NULL */
const double *comp_frac, /* Injection fraction or NULL */
const int *cells ,
const double *WI , /* Well index per perf (or NULL) */
struct Wells *W )
/* ---------------------------------------------------------------------- */
{
int ok, nw, nperf_tot, off;
int ok, nw, np, nperf_tot, off;
int nwalloc, nperfalloc;
struct WellMgmt *m;
@ -459,8 +469,9 @@ add_well(enum WellType type ,
W->type [nw] = type ;
W->depth_ref[nw] = depth_ref;
if (zfrac != NULL) {
memcpy(W->zfrac + 3*nw, zfrac, 3 * sizeof *W->zfrac);
np = W->number_of_phases;
if (comp_frac != NULL) {
memcpy(W->comp_frac + np*nw, comp_frac, np * sizeof *W->comp_frac);
}
W->well_connpos[nw + 1] = off + nperf;
@ -473,15 +484,22 @@ add_well(enum WellType type ,
/* ---------------------------------------------------------------------- */
int
append_well_controls(enum WellControlType type ,
append_well_controls(enum WellControlType type,
double target,
struct WellControls *ctrl )
const double *distr,
int well_index,
struct Wells *W)
/* ---------------------------------------------------------------------- */
{
int ok, alloc;
int ok, alloc, p, np;
struct WellControls *ctrl;
struct WellControlMgmt *m;
assert (W != NULL);
ctrl = W->ctrls[well_index];
np = W->number_of_phases;
assert (ctrl != NULL);
m = ctrl->data;
@ -489,13 +507,17 @@ append_well_controls(enum WellControlType type ,
if (! ok) {
alloc = alloc_size(ctrl->num, 1, m->cpty);
ok = well_controls_reserve(alloc, ctrl);
ok = well_controls_reserve(alloc, np, ctrl);
}
if (ok) {
ctrl->type [ctrl->num] = type ;
ctrl->target[ctrl->num] = target;
if (distr != NULL) {
for (p = 0; p < np; ++p) {
ctrl->distr[ctrl->num * np + p] = distr[p];
}
}
ctrl->num += 1;
}
@ -505,10 +527,21 @@ append_well_controls(enum WellControlType type ,
/* ---------------------------------------------------------------------- */
void
clear_well_controls(struct WellControls *ctrl)
set_current_control(int well_index, int current_control, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
if (ctrl != NULL) {
ctrl->num = 0;
assert (W->ctrls[well_index] != NULL);
W->ctrls[well_index]->current = current_control;
}
/* ---------------------------------------------------------------------- */
void
clear_well_controls(int well_index, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
if (W->ctrls[well_index] != NULL) {
W->ctrls[well_index]->num = 0;
}
}