opm-core/hybsys_global.c
2010-09-13 16:11:15 +00:00

378 lines
9.2 KiB
C

#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "hash_set.h"
#include "hybsys_global.h"
#if defined MAX
#undef MAX
#endif
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/* ---------------------------------------------------------------------- */
static void
delete_cell_wells(int *cwpos, int *cwells)
/* ---------------------------------------------------------------------- */
{
free(cwells);
free(cwpos);
}
/* ---------------------------------------------------------------------- */
static int
build_cell_wells(size_t nc, well_t *W, int **cwpos, int **cwells)
/* ---------------------------------------------------------------------- */
{
int ret, w;
int *p, *cw, *c, *connpos;
size_t i;
ret = 0;
p = calloc(nc + 1, sizeof *p);
cw = NULL;
if (p != NULL) {
connpos = W->well_connpos;
c = W->well_cells;
for (w = 0; w < W->number_of_wells; w++) {
for (; c != W->well_cells + connpos[w + 1]; c++) {
p[*c + 1] += 1;
}
}
for (i = 1; i <= nc; i++) {
p[0] += p[i];
p[i] = p[0] - p[i];
}
cw = malloc(p[0] * sizeof *cw);
if (cw != NULL) {
ret = p[0]; /* Success */
p[0] = 0;
c = W->well_cells;
for (w = 0; w < W->number_of_wells; w++) {
for (; c != W->well_cells + connpos[w + 1]; c++) {
cw[ p[*c + 1] ++ ] = w;
}
}
} else {
free(p); p = NULL;
}
}
*cwpos = p;
*cwells = cw;
return ret;
}
/* ---------------------------------------------------------------------- */
static void
deallocate_well_dofset(size_t nw, struct hash_set **wia)
/* ---------------------------------------------------------------------- */
{
size_t w;
if (wia != NULL) {
for (w = 0; w < nw; w++) {
hash_set_deallocate(wia[w]);
}
}
free(wia);
}
/* ---------------------------------------------------------------------- */
static struct hash_set **
allocate_well_dofset(grid_t *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int w, i, c, ok;
int set_size;
struct hash_set **wia;
wia = malloc(W->number_of_wells * sizeof *wia);
if (wia != NULL) {
ok = 1;
for (w = 0; ok && (w < W->number_of_wells); w++) {
set_size = 1; /* Approximate expected set size */
for (i = W->well_connpos[w]; i < W->well_connpos[w + 1]; i++) {
c = W->well_cells[i];
set_size += G->cell_facepos[c + 1] - G->cell_facepos[c];
}
wia[w] = hash_set_allocate(set_size);
ok = wia[w] != NULL;
}
if (!ok) {
deallocate_well_dofset(w, wia);
wia = NULL;
}
}
return wia;
}
/* ---------------------------------------------------------------------- */
static void
count_conn_per_row_grid(grid_t *G, struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, nc, *ia, *ja;
size_t m;
nc = G->number_of_cells;
ia = G->cell_facepos;
ja = G->cell_faces;
A->ia[0] = 0;
for (m = 0; m < A->m; m++) {
A->ia[m + 1] = 1;
}
for (c = 0; c < nc; c++) {
for (; ja != G->cell_faces + ia[c + 1]; ja++) {
A->ia[ *ja + 1 ] += ia[c + 1] - ia[c] - 1;
}
}
}
/* ---------------------------------------------------------------------- */
static int
count_conn_per_row_well(grid_t *G, well_t *W,
int *cwpos,
int *cwells,
struct hash_set **wia,
struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, w, nc, nf, nwdof, ok, i, dof, *ia, *ja, *wja;
size_t m;
nc = G->number_of_cells;
nf = G->number_of_faces;
ia = G->cell_facepos;
wja = cwells;
ok = 1;
for (c = 0; c < nc; c++) {
for (; ok && (wja != cwells + cwpos[c + 1]); wja++) {
for ( ja = G->cell_faces + ia[c + 0];
ok && (ja != G->cell_faces + ia[c + 1]); ja++) {
dof = *ja;
ok = hash_set_insert(dof, wia[*wja]) == dof;
}
for (i = cwpos[c]; ok && (i < cwpos[c + 1]); i++) {
dof = nf + cwells[i];
ok = hash_set_insert(dof, wia[*wja]) == dof;
}
}
}
if (ok) {
for (w = 0; w < W->number_of_wells; i++) {
nwdof = 0;
for (m = 0; m < wia[w]->m; m++) {
if ((dof = wia[w]->s[m]) >= 0) {
A->ia[ dof + 1 ] += 1; /* face to well */
nwdof += 1; /* well to face */
}
}
A->ia[ nf + i + 1 ] = nwdof;
}
}
return ok;
}
/* ---------------------------------------------------------------------- */
static void
fill_self_connections(struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
size_t r;
for (r = 0; r < A->m; r++) {
A->ja[ A->ia[r + 1] ++ ] = r;
}
A->n = A->m;
}
/* ---------------------------------------------------------------------- */
static void
fill_grid_connections(grid_t *G, struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int c, i, j, n;
int dof1, dof2;
int *ia, *ja;
ia = G->cell_facepos;
ja = G->cell_faces;
for (c = 0; c < G->number_of_cells; c++) {
n = ia[c + 1] - ia[c];
for (i = 0; i < n; i++) {
dof1 = ja[ ia[c] + i ];
if (dof1 >= 0) {
A->n = MAX(A->n, (size_t) dof1);
}
for (j = (i + 1) % n; j != i; j = (j + 1) % n) {
dof2 = ja[ ia[c] + j ];
A->ja[ A->ia[dof1 + 1] ++ ] = dof2;
}
}
}
}
/* ---------------------------------------------------------------------- */
static void
fill_well_connections(int nf, int nw,
struct hash_set **wia,
struct CSRMatrix *A)
/* ---------------------------------------------------------------------- */
{
int w, dof;
size_t i;
for (w = 0; w < nw; w++) {
for (i = 0; i < wia[w]->m; i++) {
dof = wia[w]->s[i];
if (dof >= 0) {
A->n = MAX(A->n, (size_t)dof);
if (dof < nf) { /* Connect face to well */
A->ja[ A->ia[ dof + 1 ] ++ ] = nf + w;
}
if (dof != nf + w) {/* Connect well to dof (avoid self) */
A->ja[ A->ia[ nf + w + 1 ] ++ ] = dof;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
struct CSRMatrix *
hybsys_define_globconn(grid_t *G, well_t *W)
/* ---------------------------------------------------------------------- */
{
int nw, ok;
int *cwell_pos = NULL, *cwells = NULL;
struct hash_set **wia;
struct CSRMatrix *A;
assert (G != NULL);
ok = 1;
nw = 0;
wia = NULL;
if (W != NULL) {
ok = build_cell_wells(G->number_of_cells, W, &cwell_pos, &cwells);
nw = ok && W->number_of_wells;
if (nw > 0) {
wia = allocate_well_dofset(G, W);
if (wia == NULL) { nw = 0; }
}
}
A = csrmatrix_new_count_nnz(G->number_of_faces + nw);
if (A != NULL) {
count_conn_per_row_grid(G, A);
if (nw > 0) {
assert (nw == W->number_of_wells);
ok = count_conn_per_row_well(G, W, cwell_pos,
cwells, wia, A) > 0;
} else {
ok = 1;
}
ok = ok && (csrmatrix_new_elms_pushback(A) > 0);
if (ok) {
fill_self_connections(A);
fill_grid_connections(G, A);
fill_well_connections(G->number_of_faces, nw, wia, A);
csrmatrix_sortrows(A);
} else {
csrmatrix_delete(A);
A = NULL;
}
}
deallocate_well_dofset(nw, wia);
delete_cell_wells(cwell_pos, cwells);
return A;
}
/* ---------------------------------------------------------------------- */
void
hybsys_global_assemble_cell(int nconn, int *conn,
const double *S,
const double *r,
struct CSRMatrix *A,
double *b)
/* ---------------------------------------------------------------------- */
{
int il, jl; /* local */
size_t ig, jg; /* global */
for (il = 0; il < nconn; il++) {
assert ((0 <= conn[il]) && ((size_t) conn[il] < A->m));
ig = conn[il];
for (jl = 0; jl < nconn; jl++) {
jg = csrmatrix_elm_index(ig, conn[jl], A);
assert ((A->ia[ig] <= (MAT_SIZE_T) jg) &&
((MAT_SIZE_T) jg < A->ia[ig + 1]));
A->sa[jg] += S[il + jl*nconn]; /* Row major per cell */
}
b[ig] += r[il];
}
}