/* Defines the basic matrix operations for the KAIJ matrix storage format. This format is used to evaluate matrices of the form: [I \otimes S + A \otimes T] where S is a dense (p \times q) matrix T is a dense (p \times q) matrix A is an AIJ (n \times n) matrix I is the identity matrix The resulting matrix is (np \times nq) We provide: MatMult() MatMultAdd() MatInvertBlockDiagonal() and MatCreateKAIJ(Mat,PetscInt,PetscInt,const PetscScalar[],const PetscScalar[],Mat*) This single directory handles both the sequential and parallel codes */ #include <../src/mat/impls/kaij/kaij.h> /*I "petscmat.h" I*/ #include <../src/mat/utils/freespace.h> #include /*@C MatKAIJGetAIJ - Get the AIJ matrix describing the blockwise action of the KAIJ matrix Not Collective, but if the KAIJ matrix is parallel, the AIJ matrix is also parallel Input Parameter: . A - the KAIJ matrix Output Parameter: . B - the AIJ matrix Level: advanced Notes: The reference count on the AIJ matrix is not increased so you should not destroy it. .seealso: MatCreateKAIJ() @*/ PetscErrorCode MatKAIJGetAIJ(Mat A,Mat *B) { PetscErrorCode ierr; PetscBool ismpikaij,isseqkaij; PetscFunctionBegin; ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIKAIJ,&ismpikaij);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQKAIJ,&isseqkaij);CHKERRQ(ierr); if (ismpikaij) { Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data; *B = b->A; } else if (isseqkaij) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; *B = b->AIJ; } else { *B = A; } PetscFunctionReturn(0); } /*@C MatKAIJGetS - Get the S matrix describing the shift action of the KAIJ matrix Not Collective, the entire S is stored and returned independently on all processes Input Parameter: . A - the KAIJ matrix Output Parameter: . S - the S matrix, in form of a scalar array in column-major format Notes: The dimensions of the output array can be determined by calling MatGetBlockSizes() on the KAIJ matrix. The row block and column block sizes returned will correspond to the number of rows and columns, respectively, in S. Level: advanced .seealso: MatCreateKAIJ(), MatGetBlockSizes() @*/ PetscErrorCode MatKAIJGetS(Mat A,const PetscScalar **S) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; PetscFunctionBegin; *S = b->S; PetscFunctionReturn(0); } /*@C MatKAIJGetT - Get the transformation matrix T associated with the KAIJ matrix Not Collective, the entire T is stored and returned independently on all processes Input Parameter: . A - the KAIJ matrix Output Parameter: . T - the T matrix, in form of a scalar array in column-major format Notes: The dimensions of the output array can be determined by calling MatGetBlockSizes() on the KAIJ matrix. The row block and column block sizes returned will correspond to the number of rows and columns, respectively, in T. Level: advanced .seealso: MatCreateKAIJ(), MatGetBlockSizes() @*/ PetscErrorCode MatKAIJGetT(Mat A,const PetscScalar **T) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; PetscFunctionBegin; *T = b->T; PetscFunctionReturn(0); } PetscErrorCode MatDestroy_SeqKAIJ(Mat A) { PetscErrorCode ierr; Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; PetscFunctionBegin; ierr = MatDestroy(&b->AIJ);CHKERRQ(ierr); ierr = PetscFree3(b->S,b->T,b->ibdiag);CHKERRQ(ierr); ierr = PetscFree5(b->sor.w,b->sor.y,b->sor.work,b->sor.t,b->sor.arr);CHKERRQ(ierr); ierr = PetscFree(A->data);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatSetUp_KAIJ(Mat A) { PetscFunctionBegin; SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Must use MatCreateKAIJ() to create KAIJ matrices"); PetscFunctionReturn(0); } PetscErrorCode MatView_SeqKAIJ(Mat A,PetscViewer viewer) { PetscErrorCode ierr; Mat B; PetscFunctionBegin; ierr = MatConvert(A,MATSEQAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr); ierr = MatView(B,viewer);CHKERRQ(ierr); ierr = MatDestroy(&B);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatView_MPIKAIJ(Mat A,PetscViewer viewer) { PetscErrorCode ierr; Mat B; PetscFunctionBegin; ierr = MatConvert(A,MATMPIAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr); ierr = MatView(B,viewer);CHKERRQ(ierr); ierr = MatDestroy(&B);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatDestroy_MPIKAIJ(Mat A) { PetscErrorCode ierr; Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data; PetscFunctionBegin; ierr = MatDestroy(&b->AIJ);CHKERRQ(ierr); ierr = MatDestroy(&b->OAIJ);CHKERRQ(ierr); ierr = MatDestroy(&b->A);CHKERRQ(ierr); ierr = VecScatterDestroy(&b->ctx);CHKERRQ(ierr); ierr = VecDestroy(&b->w);CHKERRQ(ierr); ierr = PetscFree3(b->S,b->T,b->ibdiag);CHKERRQ(ierr); ierr = PetscFree(A->data);CHKERRQ(ierr); PetscFunctionReturn(0); } /*MC MATKAIJ - MATKAIJ = "kaij" - A matrix type to be used to evaluate matrices of the following form: [I \otimes S + A \otimes T] where S is a dense (p \times q) matrix T is a dense (p \times q) matrix A is an AIJ (n \times n) matrix I is the identity matrix The resulting matrix is (np \times nq) The matrix type is based on MATSEQAIJ for a sequential matrix A, and MATMPIAIJ for a distributed matrix A. S and T are always stored independently on all processes as a PetscScalar array in column-major format. Operations provided: . MatMult . MatMultAdd . MatInvertBlockDiagonal Level: advanced .seealso: MatKAIJGetAIJ(), MatKAIJGetS(), MatKAIJGetT(), MatCreateKAIJ() M*/ PETSC_EXTERN PetscErrorCode MatCreate_KAIJ(Mat A) { PetscErrorCode ierr; Mat_MPIKAIJ *b; PetscMPIInt size; PetscFunctionBegin; ierr = PetscNewLog(A,&b);CHKERRQ(ierr); A->data = (void*)b; ierr = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr); A->ops->setup = MatSetUp_KAIJ; b->w = 0; ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); if (size == 1) { ierr = PetscObjectChangeTypeName((PetscObject)A,MATSEQKAIJ);CHKERRQ(ierr); } else { ierr = PetscObjectChangeTypeName((PetscObject)A,MATMPIKAIJ);CHKERRQ(ierr); } PetscFunctionReturn(0); } /* --------------------------------------------------------------------------------------*/ /* zz = yy + Axx */ PetscErrorCode KAIJMultAdd_Seq(Mat A,Vec xx,Vec yy,Vec zz) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; Mat_SeqAIJ *a = (Mat_SeqAIJ*)b->AIJ->data; const PetscScalar *s = b->S, *t = b->T; const PetscScalar *x,*v,*bx; PetscScalar *y,*sums; PetscErrorCode ierr; const PetscInt m = b->AIJ->rmap->n,*idx,*ii; PetscInt n,i,jrow,j,l,p=b->p,q=b->q,k; PetscFunctionBegin; if (!yy) { ierr = VecSet(zz,0.0);CHKERRQ(ierr); } else { ierr = VecCopy(yy,zz);CHKERRQ(ierr); } if ((!s) && (!t) && (!b->isTI)) PetscFunctionReturn(0); ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr); ierr = VecGetArray(zz,&y);CHKERRQ(ierr); idx = a->j; v = a->a; ii = a->i; if (b->isTI) { for (i=0; iAIJ->cmap->n) { for (j=0; jnz);CHKERRQ(ierr); ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr); ierr = VecRestoreArray(zz,&y);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatMult_SeqKAIJ_N(Mat A,Vec xx,Vec yy) { PetscErrorCode ierr; PetscFunctionBegin; ierr = KAIJMultAdd_Seq(A,xx,PETSC_NULL,yy);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatMultAdd_SeqKAIJ_N(Mat A,Vec xx,Vec yy,Vec zz) { PetscErrorCode ierr; PetscFunctionBegin; ierr = KAIJMultAdd_Seq(A,xx,yy,zz);CHKERRQ(ierr); PetscFunctionReturn(0); } #include PetscErrorCode MatInvertBlockDiagonal_SeqKAIJ_N(Mat A,const PetscScalar **values) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data; Mat_SeqAIJ *a = (Mat_SeqAIJ*)b->AIJ->data; const PetscScalar *S = b->S; const PetscScalar *T = b->T; const PetscScalar *v = a->a; const PetscInt p = b->p, q = b->q, m = b->AIJ->rmap->n, *idx = a->j, *ii = a->i; PetscErrorCode ierr; PetscInt i,j,*v_pivots,dof,dof2; PetscScalar *diag,aval,*v_work; PetscFunctionBegin; if (p != q) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MATKAIJ: Block size must be square to calculate inverse."); if ((!S) && (!T) && (!b->isTI)) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MATKAIJ: Cannot invert a zero matrix."); dof = p; dof2 = dof*dof; if (b->ibdiagvalid) { if (values) *values = b->ibdiag; PetscFunctionReturn(0); } if (!b->ibdiag) { ierr = PetscMalloc(dof2*m*sizeof(PetscScalar),&b->ibdiag);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)A,dof2*m*sizeof(PetscScalar));CHKERRQ(ierr); } if (values) *values = b->ibdiag; diag = b->ibdiag; ierr = PetscMalloc2(dof,&v_work,dof,&v_pivots);CHKERRQ(ierr); for (i=0; iisTI) { aval = 0; for (j=ii[i]; jibdiagvalid = PETSC_TRUE; PetscFunctionReturn(0); } static PetscErrorCode MatGetDiagonalBlock_MPIKAIJ(Mat A,Mat *B) { Mat_MPIKAIJ *kaij = (Mat_MPIKAIJ*) A->data; PetscFunctionBegin; *B = kaij->AIJ; PetscFunctionReturn(0); } PetscErrorCode MatSOR_SeqKAIJ(Mat A,Vec bb,PetscReal omega,MatSORType flag,PetscReal fshift,PetscInt its,PetscInt lits,Vec xx) { PetscErrorCode ierr; Mat_SeqKAIJ *kaij = (Mat_SeqKAIJ*) A->data; Mat_SeqAIJ *a = (Mat_SeqAIJ*)kaij->AIJ->data; const PetscScalar *aa = a->a, *T = kaij->T, *v; const PetscInt m = kaij->AIJ->rmap->n, *ai=a->i, *aj=a->j, p = kaij->p, q = kaij->q, *diag, *vi; const PetscScalar *b, *xb, *idiag; PetscScalar *x, *work, *workt, *w, *y, *arr, *t, *arrt; PetscInt i, j, k, i2, bs, bs2, nz; PetscFunctionBegin; its = its*lits; if (flag & SOR_EISENSTAT) SETERRQ (PETSC_COMM_SELF,PETSC_ERR_SUP,"No support yet for Eisenstat"); if (its <= 0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Relaxation requires global its %D and local its %D both positive",its,lits); if (fshift) SETERRQ (PETSC_COMM_SELF,PETSC_ERR_SUP,"Sorry, no support for diagonal shift"); if ((flag & SOR_APPLY_UPPER) || (flag & SOR_APPLY_LOWER)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Sorry, no support for applying upper or lower triangular parts"); if (p != q) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatSOR for KAIJ: Sorry, no support for non-square dense blocks"); else {bs = p; bs2 = bs*bs; } if (!m) PetscFunctionReturn(0); if (!kaij->ibdiagvalid) { ierr = MatInvertBlockDiagonal_SeqKAIJ_N(A,NULL);CHKERRQ(ierr); } idiag = kaij->ibdiag; diag = a->diag; if (!kaij->sor.setup) { ierr = PetscMalloc5(bs,&kaij->sor.w,bs,&kaij->sor.y,m*bs,&kaij->sor.work,m*bs,&kaij->sor.t,m*bs2,&kaij->sor.arr);CHKERRQ(ierr); kaij->sor.setup = PETSC_TRUE; } y = kaij->sor.y; w = kaij->sor.w; work = kaij->sor.work; t = kaij->sor.t; arr = kaij->sor.arr; ierr = VecGetArray(xx,&x); CHKERRQ(ierr); ierr = VecGetArrayRead(bb,&b);CHKERRQ(ierr); if (flag & SOR_ZERO_INITIAL_GUESS) { if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { PetscKernel_w_gets_Ar_times_v(bs,bs,b,idiag,x); /* x[0:bs] <- D^{-1} b[0:bs] */ ierr = PetscMemcpy(t,b,bs*sizeof(PetscScalar));CHKERRQ(ierr); i2 = bs; idiag += bs2; for (i=1; iisTI) { for (k=0; knz);CHKERRQ(ierr); xb = t; } else xb = b; if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) { idiag = kaij->ibdiag+bs2*(m-1); i2 = bs * (m-1); ierr = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr); PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,x+i2); i2 -= bs; idiag -= bs2; for (i=m-2; i>=0; i--) { v = aa + diag[i] + 1 ; vi = aj + diag[i] + 1; nz = ai[i+1] - diag[i] - 1; if (T) { /* FIXME: This branch untested */ ierr = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr); /* copy all rows of x that are needed into contiguous space */ workt = work; for (j=0; jisTI) { for (k=0; knz));CHKERRQ(ierr); } its--; } while (its--) { /* FIXME: This branch not updated */ if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) { i2 = 0; idiag = kaij->ibdiag; for (i=0; iisTI) { for (j=0; jisTI) { for (j=0; jibdiag+bs2*(m-1); i2 = bs * (m-1); if (xb == b) { for (i=m-1; i>=0; i--) { ierr = PetscMemcpy(w,b+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr); v = aa + ai[i]; vi = aj + ai[i]; nz = diag[i] - ai[i]; workt = work; for (j=0; jisTI) { for (j=0; jisTI) { for (j=0; j=0; i--) { ierr = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr); v = aa + diag[i] + 1; vi = aj + diag[i] + 1; nz = ai[i+1] - diag[i] - 1; workt = work; for (j=0; jisTI) { for (j=0; jnz));CHKERRQ(ierr); } } ierr = VecRestoreArray(xx,&x); CHKERRQ(ierr); ierr = VecRestoreArrayRead(bb,&b);CHKERRQ(ierr); PetscFunctionReturn(0); } /*===================================================================================*/ PetscErrorCode KAIJMultAdd_MPI(Mat A,Vec xx,Vec yy,Vec zz) { Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data; PetscErrorCode ierr; PetscFunctionBegin; if (!yy) { ierr = VecSet(zz,0.0);CHKERRQ(ierr); } else { ierr = VecCopy(yy,zz);CHKERRQ(ierr); } /* start the scatter */ ierr = VecScatterBegin(b->ctx,xx,b->w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = (*b->AIJ->ops->multadd)(b->AIJ,xx,zz,zz);CHKERRQ(ierr); ierr = VecScatterEnd(b->ctx,xx,b->w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = (*b->OAIJ->ops->multadd)(b->OAIJ,b->w,zz,zz);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatMult_MPIKAIJ_dof(Mat A,Vec xx,Vec yy) { PetscErrorCode ierr; PetscFunctionBegin; ierr = KAIJMultAdd_MPI(A,xx,PETSC_NULL,yy);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatMultAdd_MPIKAIJ_dof(Mat A,Vec xx,Vec yy, Vec zz) { PetscErrorCode ierr; PetscFunctionBegin; ierr = KAIJMultAdd_MPI(A,xx,yy,zz);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode MatInvertBlockDiagonal_MPIKAIJ_dof(Mat A,const PetscScalar **values) { Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = (*b->AIJ->ops->invertblockdiagonal)(b->AIJ,values);CHKERRQ(ierr); PetscFunctionReturn(0); } /* ----------------------------------------------------------------*/ PetscErrorCode MatGetRow_SeqKAIJ(Mat A,PetscInt row,PetscInt *ncols,PetscInt **cols,PetscScalar **values) { Mat_SeqKAIJ *b = (Mat_SeqKAIJ*) A->data; PetscErrorCode ierr,diag; PetscInt nzaij,nz,*colsaij,*idx,i,j,p=b->p,q=b->q,r=row/p,s=row%p,c; PetscScalar *vaij,*v,*S=b->S,*T=b->T; PetscFunctionBegin; if (b->getrowactive) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Already active"); b->getrowactive = PETSC_TRUE; if (row < 0 || row >= A->rmap->n) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Row %D out of range",row); if ((!S) && (!T) && (!b->isTI)) { if (ncols) *ncols = 0; if (cols) *cols = NULL; if (values) *values = NULL; PetscFunctionReturn(0); } if (T || b->isTI) { ierr = MatGetRow_SeqAIJ(b->AIJ,r,&nzaij,&colsaij,&vaij);CHKERRQ(ierr); diag = PETSC_FALSE; c = nzaij; for (i=0; iisTI) nz += (diag && S ? (nzaij-1)*q : nzaij*q); if (cols || values) { ierr = PetscMalloc2(nz,&idx,nz,&v);CHKERRQ(ierr); if (b->isTI) { for (i=0; idata)->getrowactive = PETSC_FALSE; PetscFunctionReturn(0); } PetscErrorCode MatGetRow_MPIKAIJ(Mat A,PetscInt row,PetscInt *ncols,PetscInt **cols,PetscScalar **values) { Mat_MPIKAIJ *b = (Mat_MPIKAIJ*) A->data; Mat MatAIJ = ((Mat_SeqKAIJ*)b->AIJ->data)->AIJ; Mat MatOAIJ = ((Mat_SeqKAIJ*)b->OAIJ->data)->AIJ; Mat AIJ = b->A; PetscErrorCode ierr; const PetscInt rstart=A->rmap->rstart,rend=A->rmap->rend,p=b->p,q=b->q,*garray; PetscInt nz,*idx,ncolsaij,ncolsoaij,*colsaij,*colsoaij,r,s,c,i,j,lrow; PetscScalar *v,*vals,*ovals,*S=b->S,*T=b->T; PetscBool diag; PetscFunctionBegin; if (b->getrowactive) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Already active"); b->getrowactive = PETSC_TRUE; if (row < rstart || row >= rend) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Only local rows"); lrow = row - rstart; if ((!S) && (!T) && (!b->isTI)) { if (ncols) *ncols = 0; if (cols) *cols = NULL; if (values) *values = NULL; PetscFunctionReturn(0); } r = lrow/p; s = lrow%p; if (T || b->isTI) { ierr = MatMPIAIJGetSeqAIJ(AIJ,NULL,NULL,&garray); ierr = MatGetRow_SeqAIJ(MatAIJ,lrow/p,&ncolsaij,&colsaij,&vals);CHKERRQ(ierr); ierr = MatGetRow_SeqAIJ(MatOAIJ,lrow/p,&ncolsoaij,&colsoaij,&ovals);CHKERRQ(ierr); diag = PETSC_FALSE; c = ncolsaij + ncolsoaij; for (i=0; iisTI) nz += (diag && S ? (ncolsaij+ncolsoaij-1)*q : (ncolsaij+ncolsoaij)*q); if (cols || values) { ierr = PetscMalloc2(nz,&idx,nz,&v);CHKERRQ(ierr); if (b->isTI) { for (i=0; idata)->getrowactive = PETSC_FALSE; PetscFunctionReturn(0); } PetscErrorCode MatCreateSubMatrix_KAIJ(Mat mat,IS isrow,IS iscol,MatReuse cll,Mat *newmat) { PetscErrorCode ierr; Mat A; PetscFunctionBegin; ierr = MatConvert(mat,MATAIJ,MAT_INITIAL_MATRIX,&A);CHKERRQ(ierr); ierr = MatCreateSubMatrix(A,isrow,iscol,cll,newmat);CHKERRQ(ierr); ierr = MatDestroy(&A);CHKERRQ(ierr); PetscFunctionReturn(0); } /* ---------------------------------------------------------------------------------- */ /*@C MatCreateKAIJ - Creates a matrix type to be used for matrices of the following form: [I \otimes S + A \otimes T] where S is a dense (p \times q) matrix T is a dense (p \times q) matrix A is an AIJ (n \times n) matrix I is the identity matrix The resulting matrix is (np \times nq) The matrix type is based on MATSEQAIJ for a sequential matrix A, and MATMPIAIJ for a distributed matrix A. S is always stored independently on all processes as a PetscScalar array in column-major format. Collective Input Parameters: + A - the AIJ matrix . S - the S matrix, stored as a PetscScalar array (column-major) . T - the T matrix, stored as a PetscScalar array (column-major) . p - number of rows in S and T - q - number of columns in S and T Output Parameter: . kaij - the new KAIJ matrix Operations provided: + MatMult . MatMultAdd . MatInvertBlockDiagonal - MatView Level: advanced .seealso: MatKAIJGetAIJ(), MATKAIJ @*/ PetscErrorCode MatCreateKAIJ(Mat A,PetscInt p,PetscInt q,const PetscScalar S[],const PetscScalar T[],Mat *kaij) { PetscErrorCode ierr; PetscMPIInt size; PetscInt n,i,j; Mat B; PetscBool isTI = PETSC_FALSE; PetscFunctionBegin; /* check if T is an identity matrix */ if (T && (p == q)) { isTI = PETSC_TRUE; for (i=0; irmap->n,q*A->cmap->n,p*A->rmap->N,q*A->cmap->N);CHKERRQ(ierr); ierr = PetscLayoutSetBlockSize(B->rmap,p);CHKERRQ(ierr); ierr = PetscLayoutSetBlockSize(B->cmap,q);CHKERRQ(ierr); ierr = PetscLayoutSetUp(B->rmap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(B->cmap);CHKERRQ(ierr); B->assembled = PETSC_TRUE; ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); if (size == 1) { Mat_SeqKAIJ *b; ierr = MatSetType(B,MATSEQKAIJ);CHKERRQ(ierr); B->ops->setup = NULL; B->ops->destroy = MatDestroy_SeqKAIJ; B->ops->view = MatView_SeqKAIJ; b = (Mat_SeqKAIJ*)B->data; b->p = p; b->q = q; b->AIJ = A; b->isTI = isTI; if (S) { ierr = PetscMalloc(p*q*sizeof(PetscScalar),&b->S);CHKERRQ(ierr); ierr = PetscMemcpy(b->S,S,p*q*sizeof(PetscScalar));CHKERRQ(ierr); } else b->S = NULL; if (T && (!isTI)) { ierr = PetscMalloc(p*q*sizeof(PetscScalar),&b->T);CHKERRQ(ierr); ierr = PetscMemcpy(b->T,T,p*q*sizeof(PetscScalar));CHKERRQ(ierr); } else b->T = NULL; B->ops->mult = MatMult_SeqKAIJ_N; B->ops->multadd = MatMultAdd_SeqKAIJ_N; B->ops->invertblockdiagonal = MatInvertBlockDiagonal_SeqKAIJ_N; B->ops->getrow = MatGetRow_SeqKAIJ; B->ops->restorerow = MatRestoreRow_SeqKAIJ; B->ops->sor = MatSOR_SeqKAIJ; } else { Mat_MPIAIJ *mpiaij = (Mat_MPIAIJ*)A->data; Mat_MPIKAIJ *b; IS from,to; Vec gvec; ierr = MatSetType(B,MATMPIKAIJ);CHKERRQ(ierr); B->ops->setup = NULL; B->ops->destroy = MatDestroy_MPIKAIJ; B->ops->view = MatView_MPIKAIJ; b = (Mat_MPIKAIJ*)B->data; b->p = p; b->q = q; b->A = A; b->isTI = isTI; if (S) { ierr = PetscMalloc(p*q*sizeof(PetscScalar),&b->S);CHKERRQ(ierr); ierr = PetscMemcpy(b->S,S,p*q*sizeof(PetscScalar));CHKERRQ(ierr); } else b->S = NULL; if (T &&(!isTI)) { ierr = PetscMalloc(p*q*sizeof(PetscScalar),&b->T);CHKERRQ(ierr); ierr = PetscMemcpy(b->T,T,p*q*sizeof(PetscScalar));CHKERRQ(ierr); } else b->T = NULL; ierr = MatCreateKAIJ(mpiaij->A,p,q,S ,T,&b->AIJ);CHKERRQ(ierr); ierr = MatCreateKAIJ(mpiaij->B,p,q,NULL,T,&b->OAIJ);CHKERRQ(ierr); ierr = VecGetSize(mpiaij->lvec,&n);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_SELF,&b->w);CHKERRQ(ierr); ierr = VecSetSizes(b->w,n*q,n*q);CHKERRQ(ierr); ierr = VecSetBlockSize(b->w,q);CHKERRQ(ierr); ierr = VecSetType(b->w,VECSEQ);CHKERRQ(ierr); /* create two temporary Index sets for build scatter gather */ ierr = ISCreateBlock(PetscObjectComm((PetscObject)A),q,n,mpiaij->garray,PETSC_COPY_VALUES,&from);CHKERRQ(ierr); ierr = ISCreateStride(PETSC_COMM_SELF,n*q,0,1,&to);CHKERRQ(ierr); /* create temporary global vector to generate scatter context */ ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),q,q*A->cmap->n,q*A->cmap->N,NULL,&gvec);CHKERRQ(ierr); /* generate the scatter context */ ierr = VecScatterCreateWithData(gvec,from,b->w,to,&b->ctx);CHKERRQ(ierr); ierr = ISDestroy(&from);CHKERRQ(ierr); ierr = ISDestroy(&to);CHKERRQ(ierr); ierr = VecDestroy(&gvec);CHKERRQ(ierr); B->ops->mult = MatMult_MPIKAIJ_dof; B->ops->multadd = MatMultAdd_MPIKAIJ_dof; B->ops->invertblockdiagonal = MatInvertBlockDiagonal_MPIKAIJ_dof; B->ops->getrow = MatGetRow_MPIKAIJ; B->ops->restorerow = MatRestoreRow_MPIKAIJ; ierr = PetscObjectComposeFunction((PetscObject)B,"MatGetDiagonalBlock_C",MatGetDiagonalBlock_MPIKAIJ);CHKERRQ(ierr); } B->ops->createsubmatrix = MatCreateSubMatrix_KAIJ; B->assembled = PETSC_TRUE; ierr = MatSetUp(B);CHKERRQ(ierr); *kaij = B; ierr = MatViewFromOptions(B,NULL,"-mat_view");CHKERRQ(ierr); PetscFunctionReturn(0); }