commit
d399b2d7cc
@ -33,26 +33,38 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** 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.
|
||||
* RESERVOIR_RATE -> Well constrained by reservoir volume flow rates.
|
||||
* SURFACE_RATE -> Well constrained by surface volume flow rates.
|
||||
/**
|
||||
* Well type indicates desired/expected well behaviour.
|
||||
*/
|
||||
enum WellControlType { BHP, RESERVOIR_RATE, SURFACE_RATE };
|
||||
enum WellType {
|
||||
INJECTOR, /**< Well is an injector */
|
||||
PRODUCER /**< Well is a producer */
|
||||
};
|
||||
|
||||
/** Controls for a single well.
|
||||
/**
|
||||
* Type of well control equation or inequality constraint.
|
||||
*/
|
||||
enum WellControlType {
|
||||
BHP, /**< Well constrained by BHP target */
|
||||
RESERVOIR_RATE, /**< Well constrained by reservoir volume flow rate */
|
||||
SURFACE_RATE /**< Well constrained by surface volume flow 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:
|
||||
* 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
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - (+) 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
|
||||
@ -65,65 +77,133 @@ enum WellControlType { BHP, RESERVOIR_RATE, SURFACE_RATE };
|
||||
*/
|
||||
struct WellControls
|
||||
{
|
||||
int num; /** Number of controls. */
|
||||
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 control */
|
||||
int current; /** Index of current active control. */
|
||||
/**
|
||||
* Number of controls.
|
||||
*/
|
||||
int num;
|
||||
|
||||
void *data; /** Internal management structure. */
|
||||
/**
|
||||
* Array of control types.
|
||||
*/
|
||||
enum WellControlType *type;
|
||||
|
||||
/**
|
||||
* Array of control targets
|
||||
*/
|
||||
double *target;
|
||||
|
||||
/**
|
||||
* Array of rate control distributions,
|
||||
* <CODE>Wells::number_of_phases</CODE> numbers for each control
|
||||
*/
|
||||
double *distr;
|
||||
|
||||
/**
|
||||
* Index of current active control.
|
||||
*/
|
||||
int current;
|
||||
|
||||
/**
|
||||
* Internal management structure.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Data structure aggregating static information about all wells in a scenario. */
|
||||
/**
|
||||
* Data structure aggregating static information about all wells in a scenario.
|
||||
*/
|
||||
struct Wells
|
||||
{
|
||||
int number_of_wells; /** Number of wells. */
|
||||
int number_of_phases; /** Number of phases. */
|
||||
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 *comp_frac; /** Component fractions for each well, size is (number_of_wells*number_of_phases).
|
||||
/**
|
||||
* Array of well types.
|
||||
*/
|
||||
enum WellType *type;
|
||||
|
||||
/**
|
||||
* Array of well types.
|
||||
*/
|
||||
double *depth_ref;
|
||||
|
||||
/**
|
||||
* Component fractions for each well. Array of size
|
||||
* <CODE>number_of_wells * number_of_phases</CODE>.
|
||||
* 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.
|
||||
double *comp_frac;
|
||||
|
||||
/**
|
||||
* Array of indices into well_cells (and WI). For a well @c w,
|
||||
* <CODE>well_connpos[w]</CODE> and <CODE>well_connpos[w+1]</CODE> are start
|
||||
* and one-beyond-end indices into the @c well_cells array for accessing
|
||||
* @c w's perforation cell indices.
|
||||
*/
|
||||
int *well_cells; /** Array of perforation cell indices.
|
||||
int *well_connpos;
|
||||
|
||||
/**
|
||||
* Array of perforation cell indices.
|
||||
* Size is number of perforations (== well_connpos[number_of_wells]).
|
||||
*/
|
||||
double *WI; /** Well productivity index, same size and structure as well_cells. */
|
||||
struct WellControls **ctrls; /** Well controls, one set of controls for each well. */
|
||||
int *well_cells;
|
||||
|
||||
char **name; /** Well names. One string for each well. */
|
||||
/**
|
||||
* Well productivity index, same size and structure as well_cells.
|
||||
*/
|
||||
double *WI;
|
||||
|
||||
void *data; /** Internal management structure. */
|
||||
|
||||
/**
|
||||
* Well controls, one set of controls for each well.
|
||||
*/
|
||||
struct WellControls **ctrls;
|
||||
|
||||
/**
|
||||
* Well names. One string for each well.
|
||||
*/
|
||||
char **name;
|
||||
|
||||
/**
|
||||
* Internal management structure.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
/** Data structure aggregating dynamic information about all wells in a scenario.
|
||||
* All arrays in this structure contain data for each perforation,
|
||||
* ordered the same as Wells::well_cells and Wells:WI. The array
|
||||
* sizes are, respectively,
|
||||
/**
|
||||
* Data structure aggregating dynamic information about all wells in a scenario.
|
||||
* All arrays in this structure contain data for each perforation, ordered the
|
||||
* same as Wells::well_cells and Wells:WI. The array sizes are, respectively,
|
||||
*
|
||||
* gpot n*NP
|
||||
* wdp NP
|
||||
* A n²*NP (matrix in column-major (i.e., Fortran) order).
|
||||
* phasemob n*NP
|
||||
*
|
||||
* in which "n" denotes the number of active fluid phases (and
|
||||
* constituent components) and "NP" is the total number of
|
||||
* perforations, <CODE>well_connpos[ number_of_wells ]</CODE>.
|
||||
* in which "n" denotes the number of active fluid phases (and constituent
|
||||
* components) and "NP" is the total number of perforations,
|
||||
* <CODE>well_connpos[ number_of_wells ]</CODE>.
|
||||
*/
|
||||
struct CompletionData
|
||||
{
|
||||
double *gpot; /** Gravity potentials. */
|
||||
double *A; /** Volumes to surface-components matrix, A = RB^{-1}. */
|
||||
double *phasemob; /** Phase mobilities. */
|
||||
/**
|
||||
* Gravity potentials.
|
||||
*/
|
||||
double *wdp;
|
||||
|
||||
/**
|
||||
* Volumes to surface-components matrix, A = RB^{-1}.
|
||||
*/
|
||||
double *A;
|
||||
|
||||
/**
|
||||
* Phase mobilities for all perforations, stored consecutively with the
|
||||
* phase index cycling the most rapidly.
|
||||
*/
|
||||
double *phasemob;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -216,9 +216,9 @@ namespace Opm
|
||||
const int nperf = wells_->well_connpos[nw];
|
||||
const int dim = grid_.dimensions;
|
||||
const double grav = gravity_ ? gravity_[dim - 1] : 0.0;
|
||||
wellperf_gpot_.clear();
|
||||
wellperf_gpot_.resize(np*nperf, 0.0);
|
||||
if (grav == 0.0) {
|
||||
wellperf_wdp_.clear();
|
||||
wellperf_wdp_.resize(nperf, 0.0);
|
||||
if (not (std::abs(grav) > 0.0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -228,9 +228,9 @@ namespace Opm
|
||||
|
||||
// Main loop, iterate over all perforations,
|
||||
// using the following formula (by phase):
|
||||
// gpot(perf) = g*(perf_z - well_ref_z)*rho(perf)
|
||||
// where the phase densities rho(perf) are taken to be
|
||||
// the densities in the perforation cell.
|
||||
// wdp(perf) = g*(perf_z - well_ref_z)*rho(perf)
|
||||
// where the total density rho(perf) is taken to be
|
||||
// sum_p (rho_p*saturation_p) in the perforation cell.
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const double ref_depth = wells_->depth_ref[w];
|
||||
for (int j = wells_->well_connpos[w]; j < wells_->well_connpos[w + 1]; ++j) {
|
||||
@ -239,7 +239,8 @@ namespace Opm
|
||||
props_.matrix(1, &state.pressure()[cell], &state.surfacevol()[np*cell], &cell, &A[0], 0);
|
||||
props_.density(1, &A[0], &rho[0]);
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
wellperf_gpot_[np*j + phase] = rho[phase]*grav*(cell_depth - ref_depth);
|
||||
const double s_phase = state.saturation()[np*cell + phase];
|
||||
wellperf_wdp_[j] += s_phase*rho[phase]*grav*(cell_depth - ref_depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,10 +479,7 @@ namespace Opm
|
||||
std::copy(cM, cM + np, wpM);
|
||||
} else {
|
||||
const double bhp = well_state.bhp()[w];
|
||||
double perf_p = bhp;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
perf_p += wellperf_gpot_[np*j + phase]*comp_frac[phase];
|
||||
}
|
||||
double perf_p = bhp + wellperf_wdp_[j];
|
||||
// Hack warning: comp_frac is used as a component
|
||||
// surface-volume variable in calls to matrix() and
|
||||
// viscosity(), but as a saturation in the call to
|
||||
@ -512,7 +510,7 @@ namespace Opm
|
||||
const double* z = &state.surfacevol()[0];
|
||||
UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_);
|
||||
CompletionData completion_data;
|
||||
completion_data.gpot = ! wellperf_gpot_.empty() ? &wellperf_gpot_[0] : 0;
|
||||
completion_data.wdp = ! wellperf_wdp_.empty() ? &wellperf_wdp_[0] : 0;
|
||||
completion_data.A = ! wellperf_A_.empty() ? &wellperf_A_[0] : 0;
|
||||
completion_data.phasemob = ! wellperf_phasemob_.empty() ? &wellperf_phasemob_[0] : 0;
|
||||
cfs_tpfa_res_wells wells_tmp;
|
||||
@ -599,7 +597,7 @@ namespace Opm
|
||||
{
|
||||
UnstructuredGrid* gg = const_cast<UnstructuredGrid*>(&grid_);
|
||||
CompletionData completion_data;
|
||||
completion_data.gpot = ! wellperf_gpot_.empty() ? const_cast<double*>(&wellperf_gpot_[0]) : 0;
|
||||
completion_data.wdp = ! wellperf_wdp_.empty() ? const_cast<double*>(&wellperf_wdp_[0]) : 0;
|
||||
completion_data.A = ! wellperf_A_.empty() ? const_cast<double*>(&wellperf_A_[0]) : 0;
|
||||
completion_data.phasemob = ! wellperf_phasemob_.empty() ? const_cast<double*>(&wellperf_phasemob_[0]) : 0;
|
||||
cfs_tpfa_res_wells wells_tmp;
|
||||
@ -636,16 +634,10 @@ namespace Opm
|
||||
// Compute well perforation pressures (not done by the C code).
|
||||
if (wells_ != 0) {
|
||||
const int nw = wells_->number_of_wells;
|
||||
const int np = props_.numPhases();
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const double* comp_frac = &wells_->comp_frac[np*w];
|
||||
for (int j = wells_->well_connpos[w]; j < wells_->well_connpos[w+1]; ++j) {
|
||||
const double bhp = well_state.bhp()[w];
|
||||
double perf_p = bhp;
|
||||
for (int phase = 0; phase < np; ++phase) {
|
||||
perf_p += wellperf_gpot_[np*j + phase]*comp_frac[phase];
|
||||
}
|
||||
well_state.perfPress()[j] = perf_p;
|
||||
well_state.perfPress()[j] = bhp + wellperf_wdp_[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace Opm
|
||||
struct cfs_tpfa_res_data* h_;
|
||||
|
||||
// ------ Data that will be modified for every solve. ------
|
||||
std::vector<double> wellperf_gpot_;
|
||||
std::vector<double> wellperf_wdp_;
|
||||
std::vector<double> initial_porevol_;
|
||||
|
||||
// ------ Data that will be modified for every solver iteration. ------
|
||||
|
@ -422,13 +422,13 @@ compute_well_compflux_and_deriv(struct cfs_tpfa_res_wells *wells ,
|
||||
{
|
||||
int c, i, w, np2;
|
||||
double pw, dp;
|
||||
double *WI, *gpot, *Ap, *pmobp;
|
||||
|
||||
double *pflux, *dpflux;
|
||||
const double *WI, *wdp, *Ap, *pmobp;
|
||||
double *pflux, *dpflux, gpot[3] = { 0.0 };
|
||||
|
||||
struct Wells *W;
|
||||
|
||||
assert (wells->W != NULL);
|
||||
assert (wells->W->number_of_phases <= 3);
|
||||
|
||||
W = wells->W;
|
||||
|
||||
@ -436,7 +436,7 @@ compute_well_compflux_and_deriv(struct cfs_tpfa_res_wells *wells ,
|
||||
assert (W->data != NULL);
|
||||
|
||||
WI = W->WI;
|
||||
gpot = wells->data->gpot;
|
||||
wdp = wells->data->wdp;
|
||||
Ap = wells->data->A;
|
||||
pmobp = wells->data->phasemob;
|
||||
|
||||
@ -449,11 +449,11 @@ compute_well_compflux_and_deriv(struct cfs_tpfa_res_wells *wells ,
|
||||
pw = wpress[w];
|
||||
|
||||
for (; i < W->well_connpos[w + 1]; i++,
|
||||
gpot += np, Ap += np2, pmobp += np,
|
||||
Ap += np2, pmobp += np,
|
||||
pflux += np, dpflux += 2 * np) {
|
||||
|
||||
c = W->well_cells[i];
|
||||
dp = pw - cpress[c];
|
||||
dp = pw + wdp[i]- cpress[c];
|
||||
|
||||
compute_darcyflux_and_deriv(np, WI[i], dp, pmobp, gpot,
|
||||
pimpl->flux_work,
|
||||
@ -909,8 +909,8 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
|
||||
{
|
||||
int w, i, c, np, np2, nc;
|
||||
int is_neumann, is_open;
|
||||
double pw, dp;
|
||||
double *WI, *gpot, *pmobp;
|
||||
double pw, dp, gpot[3] = { 0.0 };
|
||||
const double *WI, *wdp, *pmobp;
|
||||
const double *Ac, *dAc;
|
||||
|
||||
struct Wells *W;
|
||||
@ -923,7 +923,7 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
|
||||
W = wells->W;
|
||||
|
||||
WI = W->WI;
|
||||
gpot = wells->data->gpot;
|
||||
wdp = wells->data->wdp;
|
||||
pmobp = wells->data->phasemob;
|
||||
|
||||
is_neumann = 1;
|
||||
@ -932,14 +932,13 @@ assemble_well_contrib(struct cfs_tpfa_res_wells *wells ,
|
||||
pw = wpress[ w ];
|
||||
is_open = W->ctrls[w]->current >= 0;
|
||||
|
||||
for (; i < W->well_connpos[w + 1];
|
||||
i++, gpot += np, pmobp += np) {
|
||||
for (; i < W->well_connpos[w + 1]; i++, pmobp += np) {
|
||||
|
||||
c = W->well_cells[ i ];
|
||||
Ac = cq->Ac + (c * np2);
|
||||
dAc = cq->dAc + (c * np2);
|
||||
|
||||
dp = pw - cpress[ c ];
|
||||
dp = pw + wdp[i] - cpress[ c ];
|
||||
|
||||
init_completion_contrib(i, np, Ac, dAc, h->pimpl);
|
||||
|
||||
@ -1091,7 +1090,7 @@ compute_wflux(int np ,
|
||||
{
|
||||
int w, c, i, p;
|
||||
double pw, dp, t;
|
||||
const double *pmob;
|
||||
const double *pmob, *wdp;
|
||||
|
||||
struct Wells *W;
|
||||
struct CompletionData *cdata;
|
||||
@ -1102,13 +1101,14 @@ compute_wflux(int np ,
|
||||
|
||||
W = wells->W;
|
||||
cdata = wells->data;
|
||||
wdp = cdata->wdp;
|
||||
|
||||
for (w = i = 0; w < W->number_of_wells; w++) {
|
||||
pw = wpress[w];
|
||||
|
||||
for (; i < W->well_connpos[w + 1]; i++) {
|
||||
c = W->well_cells[ i ];
|
||||
dp = pw - cpress[c];
|
||||
dp = pw + wdp[ i ] - cpress[c];
|
||||
|
||||
if (dp > 0) { pmob = cdata->phasemob + (i * np); } /* w->c */
|
||||
else { pmob = pmobc + (c * np); } /* c->w */
|
||||
|
@ -25,6 +25,37 @@
|
||||
|
||||
#include <opm/core/pressure/tpfa/compr_source.h>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Public interface to assembler for (compressible) discrete pressure system
|
||||
* based on two-point flux approximation method. The assembler implements a
|
||||
* residual formulation that for a single cell \f$i\f$ reads
|
||||
* \f[
|
||||
* \mathit{pv}_i\cdot (1 - \sum_\alpha A_i^{-1}(p^{n+1},z^n)z^n) +
|
||||
* \Delta t\sum_\alpha A_i^{-1}(p^{n+1},z^n) \Big(\sum_j A_{ij}v_{ij}^{n+1} -
|
||||
* q_i^{n+1}\Big) = 0
|
||||
* \f]
|
||||
* in which \f$\mathit{pv}_i\f$ is the (constant or pressure-dependent)
|
||||
* pore-volume of cell \f$i\f$. Moreover, \f$\Delta t\f$ is the time step size,
|
||||
* \f$n\f$ denotes the time level, \f$A\f$ is the pressure and mass-dependent
|
||||
* fluid matrix that converts phase volumes at reservoir conditions into
|
||||
* component volumes at surface conditions and \f$v_{ij}\f$ is the vector of
|
||||
* outward (with respect to cell \f$i\f$) phase fluxes across the \f$ij\f$
|
||||
* cell-interface.
|
||||
*
|
||||
* This module's usage model is intended to be
|
||||
* -# Construct assembler
|
||||
* -# for (each time step)
|
||||
* -# while (pressure not converged)
|
||||
* -# Assemble appropriate (Jacobian) system of linear equations
|
||||
* -# Solve Jacobian system to derive pressure increments
|
||||
* -# Include increments into current state
|
||||
* -# Check convergence
|
||||
* -# Derive fluxes and, optionally, interface pressures
|
||||
* -# Solve transport by some means
|
||||
* -# Destroy assembler
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -33,36 +64,121 @@ struct cfs_tpfa_res_impl;
|
||||
struct CSRMatrix;
|
||||
struct compr_quantities_gen;
|
||||
|
||||
/**
|
||||
* Type encapsulating well topology and completion data (e.g., phase mobilities
|
||||
* per connection (perforation)).
|
||||
*/
|
||||
struct cfs_tpfa_res_wells {
|
||||
/**
|
||||
* All wells pertaining to a particular linear system assembly.
|
||||
* Must include current controls/targets and complete well topology.
|
||||
*/
|
||||
struct Wells *W ;
|
||||
|
||||
/**
|
||||
* Completion data describing the fluid state at the current time level.
|
||||
*/
|
||||
struct CompletionData *data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type encapsulating all driving forces affecting the discrete pressure system.
|
||||
*/
|
||||
struct cfs_tpfa_res_forces {
|
||||
struct cfs_tpfa_res_wells *wells;
|
||||
struct compr_src *src ;
|
||||
struct cfs_tpfa_res_wells *wells; /**< Wells */
|
||||
struct compr_src *src ; /**< Explicit source terms */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Result structure that presents the fully assembled system of linear
|
||||
* equations, linearised around the current pressure point.
|
||||
*/
|
||||
struct cfs_tpfa_res_data {
|
||||
struct CSRMatrix *J;
|
||||
double *F;
|
||||
struct CSRMatrix *J; /**< Jacobian matrix */
|
||||
double *F; /**< Residual vector (right-hand side) */
|
||||
|
||||
struct cfs_tpfa_res_impl *pimpl;
|
||||
struct cfs_tpfa_res_impl *pimpl; /**< Internal management structure */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct assembler for system of linear equations.
|
||||
*
|
||||
* @param[in] G Grid
|
||||
* @param[in] wells Well description. @c NULL in case of no wells.
|
||||
* For backwards compatibility, the constructor also
|
||||
* interprets <CODE>(wells != NULL) &&
|
||||
* (wells->W == NULL)</CODE> as "no wells present", but new
|
||||
* code should use <CODE>wells == NULL</CODE> to signify
|
||||
* "no wells".
|
||||
* @param[in] nphases Number of active fluid phases in this simulation run.
|
||||
* Needed to correctly size various internal work arrays.
|
||||
* @return Fully formed assembler structure suitable for forming systems of
|
||||
* linear equations using, e.g., function cfs_tpfa_res_assemble(). @c NULL in
|
||||
* case of allocation failure. Must be destroyed using function
|
||||
* cfs_tpfa_res_destroy().
|
||||
*/
|
||||
struct cfs_tpfa_res_data *
|
||||
cfs_tpfa_res_construct(struct UnstructuredGrid *G ,
|
||||
struct cfs_tpfa_res_wells *wells ,
|
||||
int nphases);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy assembler for system of linear equations.
|
||||
*
|
||||
* Disposes of all resources acquired in a previous call to construction
|
||||
* function cfs_tpfa_res_construct(). Note that the statement
|
||||
* <CODE>
|
||||
* cfs_tpfa_res_destroy(NULL)
|
||||
* </CODE>
|
||||
* is supported and benign (i.e., behaves like <CODE>free(NULL)</CODE>).
|
||||
*
|
||||
* @param[in,out] h On input - assembler obtained through a previous call to
|
||||
* construction function cfs_tpfa_res_construct(). On output - invalid pointer.
|
||||
*/
|
||||
void
|
||||
cfs_tpfa_res_destroy(struct cfs_tpfa_res_data *h);
|
||||
|
||||
/* Return value is 1 if the assembled matrix was adjusted to remove a
|
||||
singularity. This happens if all fluids are incompressible and
|
||||
there are no pressure conditions on wells or boundaries.
|
||||
Otherwise return 0. */
|
||||
|
||||
/**
|
||||
* Assemble system of linear equations by linearising the residual around the
|
||||
* current pressure point. Assume incompressible rock (i.e., that the
|
||||
* pore-volume is independent of pressure).
|
||||
*
|
||||
* The fully assembled system is presented in <CODE>h->J</CODE> and
|
||||
* <CODE>h->F</CODE> and must be solved separately using external software.
|
||||
*
|
||||
* @param[in] G Grid.
|
||||
* @param[in] dt Time step size \f$\Delta t\f$.
|
||||
* @param[in] forces Driving forces.
|
||||
* @param[in] zc Component volumes, per pore-volume, at surface
|
||||
* conditions for all components in all cells stored
|
||||
* consecutively per cell. Array of size
|
||||
* <CODE>G->number_of_cells * cq->nphases</CODE>.
|
||||
* @param[in] cq Compressible quantities describing the current fluid
|
||||
* state. Fields @c Ac, @c dAc, @c Af, and
|
||||
* @c phasemobf must be valid.
|
||||
* @param[in] trans Background transmissibilities as defined by function
|
||||
* tpfa_trans_compute().
|
||||
* @param[in] gravcap_f Discrete gravity and capillary forces.
|
||||
* @param[in] cpress Cell pressures. One scalar value per grid cell.
|
||||
* @param[in] wpress Well (bottom-hole) pressures. One scalar value per
|
||||
* well. @c NULL in case of no wells.
|
||||
* @param[in] porevol Pore-volumes. One (positive) scalar value for each
|
||||
* grid cell.
|
||||
* @param[in,out] h On input-a valid (non-@c NULL) assembler obtained
|
||||
* from a previous call to constructor function
|
||||
* cfs_tpfa_res_construct(). On output-valid assembler
|
||||
* that includes the new system of linear equations in
|
||||
* its @c J and @c F fields.
|
||||
*
|
||||
* @return 1 if the assembled matrix was adjusted to remove a singularity. This
|
||||
* happens if all fluids are incompressible and there are no pressure conditions
|
||||
* on wells or boundaries. Otherwise return 0.
|
||||
*/
|
||||
int
|
||||
cfs_tpfa_res_assemble(struct UnstructuredGrid *G,
|
||||
double dt,
|
||||
@ -76,11 +192,48 @@ cfs_tpfa_res_assemble(struct UnstructuredGrid *G,
|
||||
const double *porevol,
|
||||
struct cfs_tpfa_res_data *h);
|
||||
|
||||
/* Return value is 1 if the assembled matrix was adjusted to remove a
|
||||
singularity. This happens if all fluids are incompressible, the
|
||||
rock is incompressible, and there are no pressure conditions on
|
||||
wells or boundaries.
|
||||
Otherwise return 0. */
|
||||
|
||||
/**
|
||||
* Assemble system of linear equations by linearising the residual around the
|
||||
* current pressure point. Assume compressible rock (i.e., that the pore-volume
|
||||
* depends on pressure).
|
||||
*
|
||||
* The fully assembled system is presented in <CODE>h->J</CODE> and
|
||||
* <CODE>h->F</CODE> and must be solved separately using external software.
|
||||
*
|
||||
* @param[in] G Grid.
|
||||
* @param[in] dt Time step size \f$\Delta t\f$.
|
||||
* @param[in] forces Driving forces.
|
||||
* @param[in] zc Component volumes, per pore-volume, at surface
|
||||
* conditions for all components in all cells stored
|
||||
* consecutively per cell. Array of size
|
||||
* <CODE>G->number_of_cells * cq->nphases</CODE>.
|
||||
* @param[in] cq Compressible quantities describing the current fluid
|
||||
* state. Fields @c Ac, @c dAc, @c Af, and
|
||||
* @c phasemobf must be valid.
|
||||
* @param[in] trans Background transmissibilities as defined by function
|
||||
* tpfa_trans_compute().
|
||||
* @param[in] gravcap_f Discrete gravity and capillary forces.
|
||||
* @param[in] cpress Cell pressures. One scalar value per grid cell.
|
||||
* @param[in] wpress Well (bottom-hole) pressures. One scalar value per
|
||||
* well. @c NULL in case of no wells.
|
||||
* @param[in] porevol Pore-volumes. One (positive) scalar value for each
|
||||
* grid cell.
|
||||
* @param[in] porevol0 Pore-volumes at start of time step (i.e., at time
|
||||
* level \f$n\f$). One (positive) scalar value for
|
||||
* each grid cell.
|
||||
* @param[in] rock_comp Rock compressibility. One non-negative scalar for
|
||||
* each grid cell.
|
||||
* @param[in,out] h On input-a valid (non-@c NULL) assembler obtained
|
||||
* from a previous call to constructor function
|
||||
* cfs_tpfa_res_construct(). On output-valid assembler
|
||||
* that includes the new system of linear equations in
|
||||
* its @c J and @c F fields.
|
||||
*
|
||||
* @return 1 if the assembled matrix was adjusted to remove a singularity. This
|
||||
* happens if all fluids are incompressible, the rock is incompressible, and
|
||||
* there are no pressure conditions on wells or boundaries. Otherwise return 0.
|
||||
*/
|
||||
int
|
||||
cfs_tpfa_res_comprock_assemble(
|
||||
struct UnstructuredGrid *G,
|
||||
@ -97,6 +250,38 @@ cfs_tpfa_res_comprock_assemble(
|
||||
const double *rock_comp,
|
||||
struct cfs_tpfa_res_data *h);
|
||||
|
||||
|
||||
/**
|
||||
* Derive interface (total) Darcy fluxes from (converged) pressure solution.
|
||||
*
|
||||
* @param[in] G Grid
|
||||
* @param[in] forces Driving forces. Must correspond to those used when
|
||||
* forming the system of linear equations, e.g., in the
|
||||
* call to function cfs_tpfa_res_assemble().
|
||||
* @param[in] np Number of fluid phases (and components).
|
||||
* @param[in] trans Background transmissibilities as defined by function
|
||||
* tpfa_trans_compute(). Must correspond to equally
|
||||
* named parameter of the assembly functions.
|
||||
* @param[in] pmobc Phase mobilities stored consecutively per cell with
|
||||
* phase index cycling the most rapidly. Array of size
|
||||
* <CODE>G->number_of_cells * np</CODE>.
|
||||
* @param[in] pmobf Phase mobilities stored consecutively per interface
|
||||
* with phase index cycling the most rapidly. Array of
|
||||
* size <CODE>G->number_of_faces * np</CODE>.
|
||||
* @param[in] gravcap_f Discrete gravity and capillary forces.
|
||||
* @param[in] cpress Cell pressure values. One (positive) scalar for each
|
||||
* grid cell.
|
||||
* @param[in] wpress Well (bottom-hole) pressure values. One (positive)
|
||||
* scalar value for each well. @c NULL in case of no
|
||||
* wells.
|
||||
* @param[out] fflux Total Darcy interface fluxes. One scalar value for
|
||||
* each interface (inter-cell connection). Array of size
|
||||
* <CODE>G->number_of_faces</CODE>.
|
||||
* @param[out] wflux Total Darcy well connection fluxes. One scalar value
|
||||
* for each well connection (perforation). Array of size
|
||||
* <CODE>forces->wells->W->well_connpos
|
||||
* [forces->wells->W->number_of_wells]</CODE>.
|
||||
*/
|
||||
void
|
||||
cfs_tpfa_res_flux(struct UnstructuredGrid *G ,
|
||||
struct cfs_tpfa_res_forces *forces ,
|
||||
@ -110,6 +295,31 @@ cfs_tpfa_res_flux(struct UnstructuredGrid *G ,
|
||||
double *fflux ,
|
||||
double *wflux );
|
||||
|
||||
|
||||
/**
|
||||
* Derive interface pressures from (converged) pressure solution.
|
||||
*
|
||||
* @param[in] G Grid
|
||||
* @param[in] np Number of fluid phases (and components).
|
||||
* @param[in] htrans Background one-sided ("half") transmissibilities as
|
||||
* defined by function tpfa_htrans_compute().
|
||||
* @param[in] pmobf Phase mobilities stored consecutively per interface
|
||||
* with phase index cycling the most rapidly. Array of
|
||||
* size <CODE>G->number_of_faces * np</CODE>.
|
||||
* @param[in] gravcap_f Discrete gravity and capillary forces.
|
||||
* @param[in] h System assembler. Must correspond to the assembler
|
||||
* state used to form the final system of linear equations
|
||||
* from which the converged pressure solution was derived.
|
||||
* @param[in] cpress Cell pressure values. One (positive) scalar for each
|
||||
* grid cell.
|
||||
* @param[in] fflux Total Darcy interface fluxes. One scalar value for
|
||||
* each interface (inter-cell connection). Array of size
|
||||
* <CODE>G->number_of_faces</CODE>. Typically computed
|
||||
* using function cfs_tpfa_res_flux().
|
||||
* @param[out] fpress Interface pressure values. One (positive) scalar for
|
||||
* each interface. Array of size
|
||||
* <CODE>G->number_of_faces</CODE>.
|
||||
*/
|
||||
void
|
||||
cfs_tpfa_res_fpress(struct UnstructuredGrid *G,
|
||||
int np,
|
||||
|
@ -22,23 +22,109 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Module defining derived fluid quantities needed to discretise compressible
|
||||
* and miscible pressure (flow) problems.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Aggregate structure that represents an atomic view of the current fluid
|
||||
* state. These quantities are used directly in the cfs_tpfa_residual module to
|
||||
* discretise a particular, linearised flow problem.
|
||||
*/
|
||||
struct compr_quantities_gen {
|
||||
int nphases; /* Number of phases/components */
|
||||
/**
|
||||
* Number of fluid phases. The pressure solvers also assume that the number
|
||||
* of fluid components (at surface conditions) equals the number of fluid
|
||||
* phases.
|
||||
*/
|
||||
int nphases;
|
||||
|
||||
double *Ac; /* RB^{-1} per cell */
|
||||
double *dAc; /* d/dp (RB^{-1}) per cell */
|
||||
double *Af; /* RB^{-1} per face */
|
||||
double *phasemobf; /* Phase mobility per face */
|
||||
double *voldiscr; /* Volume discrepancy per cell */
|
||||
/**
|
||||
* Pressure and mass-dependent fluid matrix that converts phase volumes at
|
||||
* reservoir conditions into component volumes at surface conditions. Obeys
|
||||
* the defining formula
|
||||
* \f[
|
||||
* A = RB^{-1}
|
||||
* \f]
|
||||
* in which \f$R\f$ denotes the miscibility ratios (i.e., the dissolved
|
||||
* gas-oil ratio, \f$R_s\f$ and the evaporated oil-gas ratio, \f$R_v\f$)
|
||||
* collected as a matrix and \f$B\f$ is the diagonal matrix of
|
||||
* formation-volume expansion factors. The function is sampled in each grid
|
||||
* cell. Array of size <CODE>nphases * nphases * nc</CODE>.
|
||||
*/
|
||||
double *Ac;
|
||||
|
||||
/**
|
||||
* Derivative of \f$A\f$ with respect to pressure,
|
||||
* \f[
|
||||
* \frac{\partial A}{\partial p} = \frac{\partial R}{\partial p}B^{-1} +
|
||||
* R\frac{\partial B^{-1}}{\partial p} = (\frac{\partial R}{\partial p} -
|
||||
* A\frac{\partial B}{\partial p})B^{-1}
|
||||
* \f]
|
||||
* sampled in each grid cell. Array of size
|
||||
* <CODE>nphases * nphases * nc</CODE>.
|
||||
*/
|
||||
double *dAc;
|
||||
|
||||
/**
|
||||
* Fluid matrix sampled at each interface. Possibly as a result of an
|
||||
* upwind calculation. Array of size <CODE>nphases * nphases * nf</CODE>.
|
||||
*/
|
||||
double *Af;
|
||||
|
||||
/**
|
||||
* Phase mobility per interface. Possibly defined through an upwind
|
||||
* calculation. Array of size <CODE>nphases * nf</CODE>.
|
||||
*/
|
||||
double *phasemobf;
|
||||
|
||||
/**
|
||||
* Deceptively named "volume-discrepancy" term. Array of size @c nc.
|
||||
* Unused by the cfs_tpfa_residual module.
|
||||
*/
|
||||
double *voldiscr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create management structure capable of storing derived fluid quantities
|
||||
* pertaining to a reservoir model of a particular size.
|
||||
*
|
||||
* The resources acquired using function compr_quantities_gen_allocate() must
|
||||
* be released using the destructor function compr_quantities_gen_deallocate().
|
||||
*
|
||||
* @param[in] nc Number of grid cells
|
||||
* @param[in] nf Number of grid interfaces
|
||||
* @param[in] np Number of fluid phases (and components)
|
||||
*
|
||||
* @return Fully formed management structure. Returns @c NULL in case of
|
||||
* allocation failure.
|
||||
*/
|
||||
struct compr_quantities_gen *
|
||||
compr_quantities_gen_allocate(size_t nc, size_t nf, int np);
|
||||
|
||||
|
||||
/**
|
||||
* Release resources acquired in a previous call to constructor function
|
||||
* compr_quantities_gen_allocate().
|
||||
*
|
||||
* Note that
|
||||
* <CODE>
|
||||
* compr_quantities_gen_deallocate(NULL)
|
||||
* </CODE>
|
||||
* is supported and benign (i.e., this statement behaves as
|
||||
* <CODE>free(NULL)</CODE>).
|
||||
*
|
||||
* @param[in,out] cq On input - compressible quantity management structure
|
||||
* obtained through a previous call to construction function
|
||||
* compr_quantities_gen_allocate(). On output - invalid pointer.
|
||||
*/
|
||||
void
|
||||
compr_quantities_gen_deallocate(struct compr_quantities_gen *cq);
|
||||
|
||||
|
@ -36,28 +36,112 @@
|
||||
#ifndef OPM_COMPR_SOURCE_H_HEADER
|
||||
#define OPM_COMPR_SOURCE_H_HEADER
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Data structures and support routines needed to represent explicit,
|
||||
* compressible source terms.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Collection of explicit, compressible source terms.
|
||||
*/
|
||||
struct compr_src {
|
||||
/**
|
||||
* Number of source terms.
|
||||
*/
|
||||
int nsrc;
|
||||
|
||||
/**
|
||||
* Source term capacity. Client code should treat this member as read-only.
|
||||
* The field is used in internal memory management.
|
||||
*/
|
||||
int cpty;
|
||||
|
||||
/**
|
||||
* Number of fluid phases.
|
||||
*/
|
||||
int nphases;
|
||||
|
||||
/**
|
||||
* Cells influenced by explicit source terms. Array of size @c cpty, the
|
||||
* @c nsrc first elements (only) of which are valid.
|
||||
*/
|
||||
int *cell;
|
||||
|
||||
/**
|
||||
* Total Darcy rate of inflow (measured at reservoir conditions) of each
|
||||
* individual source term. Sign convention: Positive rate into reservoir
|
||||
* (i.e., injection) and negative rate out of reservoir (production).
|
||||
* Array of size @c cpty, the @c nsrc first elements (only) of which are
|
||||
* valid.
|
||||
*/
|
||||
double *flux;
|
||||
|
||||
/**
|
||||
* Injection composition for all explicit source terms. Not referenced for
|
||||
* production sources (i.e., those terms for which <CODE>->flux[]</CODE> is
|
||||
* negative). Array of size <CODE>nphases * cpty</CODE>, the
|
||||
* <CODE>nphases * nsrc</CODE> of which (only) are valid.
|
||||
*/
|
||||
double *saturation;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a management structure that is, initially, capable of storing a
|
||||
* specified number of sources defined by a particular number a fluid phases.
|
||||
*
|
||||
* @param[in] np Number of fluid phases. Must be positive to actually
|
||||
* allocate any sources.
|
||||
* @param[in] nsrc Initial management capacity. If positive, attempt to
|
||||
* allocate that number of source terms. Otherwise, the
|
||||
* initial capacity is treated as (and set to) zero.
|
||||
* @return Fully formed management structure if <CODE>np > 0</CODE> and
|
||||
* allocation success. @c NULL otherwise. The resources must be released using
|
||||
* destructor function compr_src_deallocate().
|
||||
*/
|
||||
struct compr_src *
|
||||
compr_src_allocate(int np, int nsrc);
|
||||
|
||||
|
||||
/**
|
||||
* Release memory resources acquired in a previous call to constructor function
|
||||
* compr_src_allocate() and, possibly, source term insertion function
|
||||
* append_compr_source_term().
|
||||
*
|
||||
* @param[in,out] src On input - source term management structure obtained
|
||||
* through a previous call to construction function compr_src_allocate().
|
||||
* On output - invalid pointer.
|
||||
*/
|
||||
void
|
||||
compr_src_deallocate(struct compr_src *src);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a new explicit source term into an existing collection.
|
||||
*
|
||||
* @param[in] c Cell influenced by this source term.
|
||||
* @param[in] np Number of fluid phases. Used for consistency checking
|
||||
* only.
|
||||
* @param[in] v Source term total reservoir volume Darcy flux. Positive
|
||||
* if the source term is to be interpreted as an injection
|
||||
* source and negative otherwise.
|
||||
* @param[in] sat Injection composition for this source term. Array of size
|
||||
* @c np. Copied to internal storage, but the actual numbers
|
||||
* are not inspected unless <CODE>v > 0.0</CODE>.
|
||||
* @param[in,out] src On input - source term management structure obtained
|
||||
* through a previous call to construction function compr_src_allocate() and,
|
||||
* possibly, another call to function append_compr_source_term(). On output -
|
||||
* source term collection that includes the new source term if successful and
|
||||
* unchanged if not.
|
||||
*
|
||||
* @return One (1, true) if successful (i.e., if the new source term could be
|
||||
* included in the existing collection) and zero (0, false) if not.
|
||||
*/
|
||||
int
|
||||
append_compr_source_term(int c ,
|
||||
int np ,
|
||||
@ -65,6 +149,15 @@ append_compr_source_term(int c ,
|
||||
const double *sat,
|
||||
struct compr_src *src);
|
||||
|
||||
|
||||
/**
|
||||
* Empty source term collection while maintaining existing capacity.
|
||||
*
|
||||
* @param[in,out] src On input - an existing source term collection with a
|
||||
* given number of sources and source capacity. On output - an empty source
|
||||
* term collection (i.e., <CODE>src->nsrc == 0</CODE>) with an unchanged
|
||||
* capacity.
|
||||
*/
|
||||
void
|
||||
clear_compr_source_term(struct compr_src *src);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user