#include "BSprivate.h"
/*@ BSforward1 - Forward triangular matrix multiplication on a single vector
Input Parameters:
. A - The sparse matrix
. x - The rhs
. comm - The communication structure for A
. procinfo - the usual processor information
Output Parameters:
. b - on exit contains A*x
Returns:
void
Notes:
We assume that A has no i-nodes or cliques
@*/
void BSforward1(BSpar_mat *A, FLOAT *x, FLOAT *b,
BScomm *comm, BSprocinfo *procinfo)
{
BMphase *to_phase, *from_phase;
BMmsg *msg;
int i, j, k;
int cl_ind, in_ind, symmetric;
int count, size, ind;
int *row;
FLOAT *nz;
BScl_2_inode *clique2inode;
BSnumbering *color2clique;
BSinode *inodes;
int *data_ptr, msg_len;
FLOAT *msg_buf;
FLOAT t;
int *gnum, *iperm;
/* Is the symmetric data structure used? */
symmetric = A->icc_storage;
color2clique = A->color2clique;
clique2inode = A->clique2inode;
inodes = A->inodes->list;
gnum = A->global_row_num->numbers;
iperm = A->inv_perm->perm;
/* post for all messages */
BMinit_comp_msg(comm->from_msg,procinfo); CHKERR(0);
if(symmetric) {
if (A->save_diag == NULL) {
/* because we know the diagonal is ones, initialize b to x */
for (i=0;i<A->num_rows;i++) b[i] = x[i];
} else {
for (i=0;i<A->num_rows;i++) b[i] = A->save_diag[i]*x[i];
}
}
/* first send my messages */
for (i=0;i<color2clique->length-1;i++) {
if(!symmetric) {
/* first multiply with the scaled diag, if any (ILU) */
for (cl_ind=color2clique->numbers[i];
cl_ind<color2clique->numbers[i+1]; cl_ind++) {
if (procinfo->my_id == clique2inode->proc[cl_ind]) {
ind = clique2inode->d_mats[cl_ind].local_ind;
if (A->scale_diag == NULL)
b[ind] = A->diag[ind]*x[ind];
else
if (A->diag[ind] > 0.0)
b[ind] = x[ind];
else if (A->diag[ind] < 0.0)
b[ind] = -x[ind];
else
b[ind] = 0.0;
}
}
}
/* now send my messages */
to_phase = BMget_phase(comm->to_msg,i); CHKERR(0);
msg = NULL;
while ((msg = BMnext_msg(to_phase,msg)) != NULL) {
CHKERR(0);
msg_buf = (FLOAT *) BMget_msg_ptr(msg); CHKERR(0);
data_ptr = BMget_user(msg,&msg_len); CHKERR(0);
for (j=0;j<msg_len;j++) {
msg_buf[j] = x[data_ptr[j]];
}
BMsendf_msg(msg,procinfo); CHKERR(0);
}
CHKERR(0);
}
/* do some local work */
for (i=0;i<color2clique->length-1;i++) {
for (cl_ind=color2clique->numbers[i];
cl_ind<color2clique->numbers[i+1];cl_ind++) {
if (procinfo->my_id == clique2inode->proc[cl_ind]) {
/* only do the strictly lower triangular part */
/* we ASSUME the diagonal is all 1's */
/* and it is taken care of above */
/* now, multiply the inodes */
in_ind=clique2inode->inode_index[cl_ind];
size = inodes[in_ind].length;
if (size > 0) {
ind = clique2inode->d_mats[cl_ind].local_ind;
row = inodes[in_ind].row_num;
nz = inodes[in_ind].nz;
t = x[ind];
for (k=0;k<size;k++) b[row[k]] += nz[k]*t;
}
}
}
}
/* receive my messages and do non-local work */
for (i=0;i<color2clique->length-1;i++) {
from_phase = BMget_phase(comm->from_msg,i); CHKERR(0);
while ((msg = BMrecv_msg(from_phase)) != NULL) {
CHKERR(0);
msg_buf = (FLOAT *) BMget_msg_ptr(msg); CHKERR(0);
data_ptr = BMget_user(msg,&msg_len); CHKERR(0);
count = 0;
for (cl_ind=data_ptr[0];cl_ind<=data_ptr[1];cl_ind++) {
in_ind=clique2inode->inode_index[cl_ind];
size = inodes[in_ind].length;
if (size > 0) {
row = inodes[in_ind].row_num;
nz = inodes[in_ind].nz;
t = msg_buf[count];
for (k=0;k<size;k++) b[row[k]] += nz[k]*t;
}
count++;
}
BMfree_msg(msg); CHKERR(0);
}
CHKERR(0);
}
/* wait for all of the sent messages to finish */
BMfinish_comp_msg(comm->to_msg,procinfo); CHKERR(0);
if(symmetric) {
MLOG_flop((2*A->local_nnz));
} else {
MLOG_flop((4*A->local_nnz-2*A->num_rows));
}
}
syntax highlighted by Code2HTML, v. 0.9.1