2014-01-05 07:47:15 -06:00
|
|
|
/*===========================================================================
|
|
|
|
//
|
|
|
|
// File: newwells.c
|
|
|
|
//
|
|
|
|
// Created: 2012-02-03 11:28:40+0100
|
|
|
|
//
|
|
|
|
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
|
|
|
|
// Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
|
|
|
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
|
|
|
|
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
|
|
|
|
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
|
|
|
|
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
|
|
|
|
//
|
|
|
|
//==========================================================================*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
|
|
|
Copyright 2012 Statoil ASA.
|
|
|
|
|
|
|
|
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 "config.h"
|
|
|
|
|
|
|
|
#include <opm/core/well_controls.h>
|
2014-01-05 09:22:30 -06:00
|
|
|
#include <assert.h>
|
2014-01-05 07:47:15 -06:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2014-01-05 09:22:30 -06:00
|
|
|
#include <stdio.h>
|
2014-01-05 07:47:15 -06:00
|
|
|
|
2014-01-06 08:13:32 -06:00
|
|
|
/**
|
|
|
|
* 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:
|
|
|
|
*
|
2015-07-08 10:40:10 -05:00
|
|
|
* - BHP -> target bottom hole pressure in Pascal.
|
|
|
|
* - THP -> target tubing head pressure in Pascal.
|
2014-01-06 08:13:32 -06:00
|
|
|
* - 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.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* value for the well.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct WellControls
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Number of controls.
|
|
|
|
*/
|
|
|
|
int num;
|
|
|
|
|
|
|
|
int number_of_phases;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of control types.
|
|
|
|
*/
|
|
|
|
enum WellControlType *type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of control targets.
|
|
|
|
*/
|
|
|
|
double *target;
|
|
|
|
|
2015-07-08 10:40:10 -05:00
|
|
|
/**
|
|
|
|
* Array of artificial lift quantities.
|
|
|
|
*/
|
|
|
|
double *alq;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of VFP table numbers
|
|
|
|
*/
|
|
|
|
int *vfp;
|
|
|
|
|
2014-01-06 08:13:32 -06:00
|
|
|
/**
|
|
|
|
* Array of rate control distributions,
|
|
|
|
* <CODE>number_of_phases</CODE> numbers for each control
|
|
|
|
*/
|
|
|
|
double *distr;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Index of current active control.
|
|
|
|
*/
|
|
|
|
int current;
|
|
|
|
|
2014-03-04 07:28:42 -06:00
|
|
|
bool well_is_open;
|
|
|
|
|
2014-01-06 08:13:32 -06:00
|
|
|
/*
|
|
|
|
The capacity allocated.
|
|
|
|
*/
|
|
|
|
int cpty;
|
|
|
|
};
|
2014-01-05 07:47:15 -06:00
|
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void
|
|
|
|
well_controls_destroy(struct WellControls *ctrl)
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
{
|
|
|
|
if (ctrl != NULL) {
|
|
|
|
free (ctrl->distr);
|
|
|
|
free (ctrl->target);
|
|
|
|
free (ctrl->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(ctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
struct WellControls *
|
|
|
|
well_controls_create(void)
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
{
|
|
|
|
struct WellControls *ctrl;
|
|
|
|
|
|
|
|
ctrl = malloc(1 * sizeof *ctrl);
|
|
|
|
|
|
|
|
if (ctrl != NULL) {
|
2014-03-04 07:28:42 -06:00
|
|
|
/* Initialise empty control set; the well is created open. */
|
2014-01-05 07:47:15 -06:00
|
|
|
ctrl->num = 0;
|
|
|
|
ctrl->number_of_phases = 0;
|
|
|
|
ctrl->type = NULL;
|
|
|
|
ctrl->target = NULL;
|
2015-07-08 10:40:10 -05:00
|
|
|
ctrl->alq = NULL;
|
|
|
|
ctrl->vfp = NULL;
|
2014-01-05 07:47:15 -06:00
|
|
|
ctrl->distr = NULL;
|
|
|
|
ctrl->current = -1;
|
2014-01-05 07:54:56 -06:00
|
|
|
ctrl->cpty = 0;
|
2014-03-04 07:28:42 -06:00
|
|
|
ctrl->well_is_open = true;
|
2014-01-05 07:47:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------- */
|
2014-01-05 09:22:30 -06:00
|
|
|
static int
|
|
|
|
well_controls_reserve(int nctrl, struct WellControls *ctrl)
|
2014-01-05 07:47:15 -06:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
{
|
|
|
|
int c, p, ok;
|
2015-07-08 10:40:10 -05:00
|
|
|
void *type, *target, *alq, *vfp, *distr;
|
2014-01-05 07:47:15 -06:00
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
type = realloc(ctrl->type , nctrl * 1 * sizeof *ctrl->type );
|
|
|
|
target = realloc(ctrl->target, nctrl * 1 * sizeof *ctrl->target);
|
2015-07-08 10:40:10 -05:00
|
|
|
alq = realloc(ctrl->alq , nctrl * 1 * sizeof *ctrl->alq );
|
|
|
|
vfp = realloc(ctrl->vfp , nctrl * 1 * sizeof *ctrl->vfp );
|
2014-01-05 09:22:30 -06:00
|
|
|
distr = realloc(ctrl->distr , nctrl * ctrl->number_of_phases * sizeof *ctrl->distr );
|
2014-01-05 07:47:15 -06:00
|
|
|
|
|
|
|
ok = 0;
|
|
|
|
if (type != NULL) { ctrl->type = type ; ok++; }
|
|
|
|
if (target != NULL) { ctrl->target = target; ok++; }
|
2015-07-08 10:40:10 -05:00
|
|
|
if (alq != NULL) { ctrl->alq = alq; ok++; }
|
|
|
|
if (vfp != NULL) { ctrl->vfp = vfp; ok++; }
|
2014-01-05 07:47:15 -06:00
|
|
|
if (distr != NULL) { ctrl->distr = distr ; ok++; }
|
|
|
|
|
2015-07-08 10:40:10 -05:00
|
|
|
if (ok == 5) {
|
2014-01-05 07:54:56 -06:00
|
|
|
for (c = ctrl->cpty; c < nctrl; c++) {
|
2014-01-05 07:47:15 -06:00
|
|
|
ctrl->type [c] = BHP;
|
|
|
|
ctrl->target[c] = -1.0;
|
|
|
|
}
|
|
|
|
|
2014-01-05 07:54:56 -06:00
|
|
|
for (p = ctrl->cpty * ctrl->number_of_phases; p < nctrl * ctrl->number_of_phases; ++p) {
|
2014-01-05 07:47:15 -06:00
|
|
|
ctrl->distr[ p ] = 0.0;
|
|
|
|
}
|
|
|
|
|
2014-01-05 07:54:56 -06:00
|
|
|
ctrl->cpty = nctrl;
|
2014-01-05 07:47:15 -06:00
|
|
|
}
|
|
|
|
|
2015-07-08 10:40:10 -05:00
|
|
|
return ok == 5;
|
2014-01-05 07:47:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-01 10:57:02 -05:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
struct WellControls *
|
|
|
|
well_controls_clone(const struct WellControls *ctrl)
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
{
|
|
|
|
int ok, i, n;
|
|
|
|
double target;
|
2015-07-08 10:40:10 -05:00
|
|
|
double alq;
|
|
|
|
int vfp;
|
2014-07-01 10:57:02 -05:00
|
|
|
const double *distr;
|
|
|
|
struct WellControls *new;
|
|
|
|
enum WellControlType type;
|
|
|
|
|
|
|
|
new = well_controls_create();
|
|
|
|
|
|
|
|
if (new != NULL) {
|
|
|
|
/* Assign appropriate number of phases */
|
|
|
|
well_controls_assert_number_of_phases(new, ctrl->number_of_phases);
|
|
|
|
|
|
|
|
n = well_controls_get_num(ctrl);
|
|
|
|
ok = well_controls_reserve(n, new);
|
|
|
|
|
|
|
|
if (! ok) {
|
|
|
|
well_controls_destroy(new);
|
|
|
|
new = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; ok && (i < n); i++) {
|
|
|
|
type = well_controls_iget_type (ctrl, i);
|
|
|
|
distr = well_controls_iget_distr (ctrl, i);
|
|
|
|
target = well_controls_iget_target(ctrl, i);
|
2015-07-08 10:40:10 -05:00
|
|
|
alq = well_controls_iget_alq (ctrl, i);
|
|
|
|
vfp = well_controls_iget_vfp (ctrl, i);
|
2014-07-01 10:57:02 -05:00
|
|
|
|
2015-07-08 10:40:10 -05:00
|
|
|
ok = well_controls_add_new(type, target, alq, vfp, distr, new);
|
2014-07-01 10:57:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (i < n) {
|
|
|
|
assert (!ok);
|
|
|
|
well_controls_destroy(new);
|
|
|
|
|
|
|
|
new = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
i = well_controls_get_current(ctrl);
|
|
|
|
well_controls_set_current(new, i);
|
|
|
|
|
|
|
|
if (well_controls_well_is_open(ctrl)) {
|
|
|
|
well_controls_open_well(new);
|
|
|
|
}
|
|
|
|
else {
|
2014-11-18 01:32:55 -06:00
|
|
|
well_controls_stop_well(new);
|
2014-07-01 10:57:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert (well_controls_equal(ctrl, new, true));
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
int well_controls_get_num(const struct WellControls *ctrl) {
|
|
|
|
return ctrl->num;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int well_controls_get_current( const struct WellControls * ctrl) {
|
|
|
|
return ctrl->current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
well_controls_set_current( struct WellControls * ctrl, int current) {
|
|
|
|
ctrl->current = current;
|
|
|
|
}
|
|
|
|
|
2014-11-18 01:32:55 -06:00
|
|
|
bool well_controls_well_is_stopped(const struct WellControls * ctrl) {
|
2014-03-04 07:28:42 -06:00
|
|
|
return !ctrl->well_is_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool well_controls_well_is_open(const struct WellControls * ctrl) {
|
|
|
|
return ctrl->well_is_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
void well_controls_open_well( struct WellControls * ctrl) {
|
|
|
|
ctrl->well_is_open = true;
|
|
|
|
}
|
|
|
|
|
2014-11-18 01:32:55 -06:00
|
|
|
void well_controls_stop_well( struct WellControls * ctrl) {
|
2014-03-04 07:28:42 -06:00
|
|
|
ctrl->well_is_open = false;
|
2014-01-06 05:06:36 -06:00
|
|
|
}
|
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
|
2014-03-04 07:28:42 -06:00
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
enum WellControlType
|
|
|
|
well_controls_iget_type(const struct WellControls * ctrl, int control_index) {
|
|
|
|
return ctrl->type[control_index];
|
|
|
|
}
|
|
|
|
|
2014-01-06 07:40:03 -06:00
|
|
|
|
|
|
|
enum WellControlType
|
|
|
|
well_controls_get_current_type(const struct WellControls * ctrl) {
|
|
|
|
return well_controls_iget_type( ctrl , ctrl->current);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-06 05:06:36 -06:00
|
|
|
void
|
|
|
|
well_controls_iset_type( struct WellControls * ctrls , int control_index , enum WellControlType type) {
|
|
|
|
ctrls->type[control_index] = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
double
|
|
|
|
well_controls_iget_target(const struct WellControls * ctrl, int control_index) {
|
|
|
|
return ctrl->target[control_index];
|
|
|
|
}
|
|
|
|
|
2014-01-06 07:40:03 -06:00
|
|
|
double
|
|
|
|
well_controls_get_current_target(const struct WellControls * ctrl) {
|
|
|
|
return ctrl->target[ctrl->current];
|
|
|
|
}
|
|
|
|
|
2014-01-06 05:06:36 -06:00
|
|
|
void
|
|
|
|
well_controls_iset_target(struct WellControls * ctrl, int control_index , double target) {
|
|
|
|
ctrl->target[control_index] = target;
|
|
|
|
}
|
|
|
|
|
2015-07-08 10:40:10 -05:00
|
|
|
double
|
|
|
|
well_controls_iget_alq(const struct WellControls * ctrl, int control_index) {
|
|
|
|
return ctrl->alq[control_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
well_controls_iset_alq(struct WellControls * ctrl, int control_index , double alq) {
|
|
|
|
ctrl->alq[control_index] = alq;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
well_controls_iget_vfp(const struct WellControls * ctrl, int control_index) {
|
|
|
|
return ctrl->vfp[control_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
well_controls_iset_vfp(struct WellControls * ctrl, int control_index , int vfp) {
|
|
|
|
ctrl->vfp[control_index] = vfp;
|
|
|
|
}
|
|
|
|
|
2014-01-06 05:06:36 -06:00
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
const double *
|
|
|
|
well_controls_iget_distr(const struct WellControls * ctrl, int control_index) {
|
|
|
|
int offset = control_index * ctrl->number_of_phases;
|
|
|
|
return &ctrl->distr[offset];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-06 07:40:03 -06:00
|
|
|
const double *
|
|
|
|
well_controls_get_current_distr(const struct WellControls * ctrl) {
|
|
|
|
return well_controls_iget_distr( ctrl , ctrl->current );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-06 05:22:15 -06:00
|
|
|
void
|
|
|
|
well_controls_iset_distr(const struct WellControls * ctrl, int control_index, const double * distr) {
|
|
|
|
int offset = control_index * ctrl->number_of_phases;
|
2015-09-03 06:55:52 -05:00
|
|
|
int p;
|
|
|
|
for (p=0; p < ctrl->number_of_phases; p++)
|
2014-01-06 05:22:15 -06:00
|
|
|
ctrl->distr[offset + p] = distr[p];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
void
|
|
|
|
well_controls_assert_number_of_phases(struct WellControls * ctrl , int number_of_phases) {
|
|
|
|
if (ctrl->num == 0)
|
|
|
|
ctrl->number_of_phases = number_of_phases;
|
|
|
|
|
|
|
|
assert( ctrl->number_of_phases == number_of_phases );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
well_controls_clear(struct WellControls * ctrl) {
|
|
|
|
ctrl->num = 0;
|
|
|
|
ctrl->number_of_phases = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2015-07-08 10:40:10 -05:00
|
|
|
well_controls_add_new(enum WellControlType type , double target , double alq , int vfp , const double * distr , struct WellControls * ctrl) {
|
2014-01-05 09:22:30 -06:00
|
|
|
if (ctrl->num == ctrl->cpty) {
|
|
|
|
int new_cpty = 2*ctrl->cpty;
|
|
|
|
if (new_cpty == ctrl->num)
|
|
|
|
new_cpty += 1;
|
|
|
|
|
|
|
|
if (!well_controls_reserve( new_cpty , ctrl))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-06 05:24:32 -06:00
|
|
|
well_controls_iset_type( ctrl , ctrl->num , type);
|
|
|
|
well_controls_iset_target( ctrl , ctrl->num , target);
|
2015-07-08 10:40:10 -05:00
|
|
|
well_controls_iset_alq(ctrl , ctrl->num , alq);
|
|
|
|
well_controls_iset_vfp(ctrl , ctrl->num , vfp);
|
2014-01-05 09:22:30 -06:00
|
|
|
|
2014-01-06 05:24:32 -06:00
|
|
|
if (distr != NULL)
|
|
|
|
well_controls_iset_distr( ctrl , ctrl->num , distr);
|
|
|
|
|
2014-01-05 09:22:30 -06:00
|
|
|
ctrl->num += 1;
|
|
|
|
return 1;
|
|
|
|
}
|
2014-01-05 07:47:15 -06:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2014-01-30 02:50:09 -06:00
|
|
|
well_controls_equal(const struct WellControls *ctrls1, const struct WellControls *ctrls2 , bool verbose)
|
2014-01-05 07:47:15 -06:00
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
{
|
|
|
|
bool are_equal = true;
|
2014-01-30 02:50:09 -06:00
|
|
|
|
|
|
|
if (ctrls1->num != ctrls2->num) {
|
|
|
|
are_equal = false;
|
|
|
|
if (verbose)
|
|
|
|
printf("ctrls1->num:%d ctrls2->num:%d \n",ctrls1->num , ctrls2->num);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctrls1->number_of_phases != ctrls2->number_of_phases) {
|
|
|
|
are_equal = false;
|
|
|
|
if (verbose)
|
|
|
|
printf("ctrls1->number_of_phases:%d ctrls2->number_of_phases:%d \n",ctrls1->number_of_phases , ctrls2->number_of_phases);
|
|
|
|
}
|
|
|
|
|
2014-01-05 07:47:15 -06:00
|
|
|
if (!are_equal) {
|
|
|
|
return are_equal;
|
|
|
|
}
|
|
|
|
|
2014-01-30 02:50:09 -06:00
|
|
|
if (memcmp(ctrls1->type, ctrls2->type, ctrls1->num * sizeof *ctrls1->type ) != 0) {
|
|
|
|
are_equal = false;
|
|
|
|
if (verbose)
|
|
|
|
printf("The ->type vectors are different \n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(ctrls1->target, ctrls2->target, ctrls1->num * sizeof *ctrls1->target ) != 0) {
|
|
|
|
are_equal = false;
|
|
|
|
if (verbose)
|
|
|
|
printf("The ->target vectors are different \n");
|
|
|
|
}
|
2014-01-05 07:47:15 -06:00
|
|
|
|
|
|
|
return are_equal;
|
|
|
|
}
|
2014-01-05 09:22:30 -06:00
|
|
|
|