/*$Id: mpidense.c,v 1.136 2000/04/09 04:35:58 bsmith Exp bsmith $*/ /* Basic functions for basic parallel dense matrices. */ #include "src/mat/impls/dense/mpi/mpidense.h" #include "src/vec/vecimpl.h" EXTERN_C_BEGIN #undef __FUNC__ #define __FUNC__ /**/"MatGetDiagonalBlock_MPIDense" int MatGetDiagonalBlock_MPIDense(Mat A,PetscTruth *iscopy,MatReuse reuse,Mat *B) { Mat_MPIDense *mdn = (Mat_MPIDense*)A->data; int m = mdn->m,rstart = mdn->rstart,rank,ierr; Scalar *array; MPI_Comm comm; PetscFunctionBegin; if (mdn->M != mdn->N) SETERRQ(PETSC_ERR_SUP,0,"Only square matrices supported."); /* The reuse aspect is not implemented efficiently */ if (reuse) { ierr = MatDestroy(*B);CHKERRQ(ierr);} ierr = MPI_Comm_rank(A->comm,&rank);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)(mdn->A),&comm);CHKERRQ(ierr); ierr = MatGetArray(mdn->A,&array);CHKERRQ(ierr); ierr = MatCreateSeqDense(comm,m,m,array+m*rstart,B);CHKERRQ(ierr); ierr = MatRestoreArray(mdn->A,&array);CHKERRQ(ierr); ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); *iscopy = PETSC_TRUE; PetscFunctionReturn(0); } EXTERN_C_END extern int MatSetUpMultiply_MPIDense(Mat); #undef __FUNC__ #define __FUNC__ /**/"MatSetValues_MPIDense" int MatSetValues_MPIDense(Mat mat,int m,int *idxm,int n,int *idxn,Scalar *v,InsertMode addv) { Mat_MPIDense *A = (Mat_MPIDense*)mat->data; int ierr,i,j,rstart = A->rstart,rend = A->rend,row; int roworiented = A->roworiented; PetscFunctionBegin; for (i=0; i= A->M) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Row too large"); if (idxm[i] >= rstart && idxm[i] < rend) { row = idxm[i] - rstart; if (roworiented) { ierr = MatSetValues(A->A,1,&row,n,idxn,v+i*n,addv);CHKERRQ(ierr); } else { for (j=0; j= A->N) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Column too large"); ierr = MatSetValues(A->A,1,&row,1,&idxn[j],v+i+j*m,addv);CHKERRQ(ierr); } } } else { if (!A->donotstash) { if (roworiented) { ierr = MatStashValuesRow_Private(&mat->stash,idxm[i],n,idxn,v+i*n);CHKERRQ(ierr); } else { ierr = MatStashValuesCol_Private(&mat->stash,idxm[i],n,idxn,v+i,m);CHKERRQ(ierr); } } } } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetValues_MPIDense" int MatGetValues_MPIDense(Mat mat,int m,int *idxm,int n,int *idxn,Scalar *v) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr,i,j,rstart = mdn->rstart,rend = mdn->rend,row; PetscFunctionBegin; for (i=0; i= mdn->M) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Row too large"); if (idxm[i] >= rstart && idxm[i] < rend) { row = idxm[i] - rstart; for (j=0; j= mdn->N) { SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Column too large"); } ierr = MatGetValues(mdn->A,1,&row,1,&idxn[j],v+i*n+j);CHKERRQ(ierr); } } else { SETERRQ(PETSC_ERR_SUP,0,"Only local values currently supported"); } } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetArray_MPIDense" int MatGetArray_MPIDense(Mat A,Scalar **array) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; int ierr; PetscFunctionBegin; ierr = MatGetArray(a->A,array);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetSubMatrix_MPIDense" static int MatGetSubMatrix_MPIDense(Mat A,IS isrow,IS iscol,int cs,MatReuse scall,Mat *B) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data,*newmatd; Mat_SeqDense *lmat = (Mat_SeqDense*)mat->A->data; int i,j,ierr,*irow,*icol,rstart,rend,nrows,ncols,nlrows,nlcols,rank; Scalar *av,*bv,*v = lmat->v; Mat newmat; PetscFunctionBegin; ierr = MPI_Comm_rank(A->comm,&rank);CHKERRQ(ierr); ierr = ISGetIndices(isrow,&irow);CHKERRQ(ierr); ierr = ISGetIndices(iscol,&icol);CHKERRQ(ierr); ierr = ISGetSize(isrow,&nrows);CHKERRQ(ierr); ierr = ISGetSize(iscol,&ncols);CHKERRQ(ierr); /* No parallel redistribution currently supported! Should really check each index set to comfirm that it is OK. ... Currently supports only submatrix same partitioning as original matrix! */ ierr = MatGetLocalSize(A,&nlrows,&nlcols);CHKERRQ(ierr); ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr); /* Check submatrix call */ if (scall == MAT_REUSE_MATRIX) { /* SETERRQ(PETSC_ERR_ARG_SIZ,0,"Reused submatrix wrong size"); */ /* Really need to test rows and column sizes! */ newmat = *B; } else { /* Create and fill new matrix */ ierr = MatCreateMPIDense(A->comm,nrows,ncols,PETSC_DECIDE,PETSC_DECIDE,PETSC_NULL,&newmat);CHKERRQ(ierr); } /* Now extract the data pointers and do the copy, column at a time */ newmatd = (Mat_MPIDense*)newmat->data; bv = ((Mat_SeqDense *)newmatd->A->data)->v; for (i=0; i*/"MatRestoreArray_MPIDense" int MatRestoreArray_MPIDense(Mat A,Scalar **array) { PetscFunctionBegin; PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatAssemblyBegin_MPIDense" int MatAssemblyBegin_MPIDense(Mat mat,MatAssemblyType mode) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; MPI_Comm comm = mat->comm; int ierr,nstash,reallocs; InsertMode addv; PetscFunctionBegin; /* make sure all processors are either in INSERTMODE or ADDMODE */ ierr = MPI_Allreduce(&mat->insertmode,&addv,1,MPI_INT,MPI_BOR,comm);CHKERRQ(ierr); if (addv == (ADD_VALUES|INSERT_VALUES)) { SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"Cannot mix adds/inserts on different procs"); } mat->insertmode = addv; /* in case this processor had no cache */ ierr = MatStashScatterBegin_Private(&mat->stash,mdn->rowners);CHKERRQ(ierr); ierr = MatStashGetInfo_Private(&mat->stash,&nstash,&reallocs);CHKERRQ(ierr); PLogInfo(mdn->A,"MatAssemblyBegin_MPIDense:Stash has %d entries, uses %d mallocs.\n",nstash,reallocs); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatAssemblyEnd_MPIDense" int MatAssemblyEnd_MPIDense(Mat mat,MatAssemblyType mode) { Mat_MPIDense *mdn=(Mat_MPIDense*)mat->data; int i,n,ierr,*row,*col,flg,j,rstart,ncols; Scalar *val; InsertMode addv=mat->insertmode; PetscFunctionBegin; /* wait on receives */ while (1) { ierr = MatStashScatterGetMesg_Private(&mat->stash,&n,&row,&col,&val,&flg);CHKERRQ(ierr); if (!flg) break; for (i=0; istash);CHKERRQ(ierr); ierr = MatAssemblyBegin(mdn->A,mode);CHKERRQ(ierr); ierr = MatAssemblyEnd(mdn->A,mode);CHKERRQ(ierr); if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) { ierr = MatSetUpMultiply_MPIDense(mat);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatZeroEntries_MPIDense" int MatZeroEntries_MPIDense(Mat A) { int ierr; Mat_MPIDense *l = (Mat_MPIDense*)A->data; PetscFunctionBegin; ierr = MatZeroEntries(l->A);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetBlockSize_MPIDense" int MatGetBlockSize_MPIDense(Mat A,int *bs) { PetscFunctionBegin; *bs = 1; PetscFunctionReturn(0); } /* the code does not do the diagonal entries correctly unless the matrix is square and the column and row owerships are identical. This is a BUG. The only way to fix it seems to be to access mdn->A and mdn->B directly and not through the MatZeroRows() routine. */ #undef __FUNC__ #define __FUNC__ /**/"MatZeroRows_MPIDense" int MatZeroRows_MPIDense(Mat A,IS is,Scalar *diag) { Mat_MPIDense *l = (Mat_MPIDense*)A->data; int i,ierr,N,*rows,*owners = l->rowners,size = l->size; int *procs,*nprocs,j,found,idx,nsends,*work; int nmax,*svalues,*starts,*owner,nrecvs,rank = l->rank; int *rvalues,tag = A->tag,count,base,slen,n,*source; int *lens,imdex,*lrows,*values; MPI_Comm comm = A->comm; MPI_Request *send_waits,*recv_waits; MPI_Status recv_status,*send_status; IS istmp; PetscFunctionBegin; ierr = ISGetSize(is,&N);CHKERRQ(ierr); ierr = ISGetIndices(is,&rows);CHKERRQ(ierr); /* first count number of contributors to each processor */ nprocs = (int*)PetscMalloc(2*size*sizeof(int));CHKPTRQ(nprocs); ierr = PetscMemzero(nprocs,2*size*sizeof(int));CHKERRQ(ierr); procs = nprocs + size; owner = (int*)PetscMalloc((N+1)*sizeof(int));CHKPTRQ(owner); /* see note*/ for (i=0; i= owners[j] && idx < owners[j+1]) { nprocs[j]++; procs[j] = 1; owner[i] = j; found = 1; break; } } if (!found) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Index out of range"); } nsends = 0; for (i=0; iA,istmp,diag);CHKERRQ(ierr); ierr = ISDestroy(istmp);CHKERRQ(ierr); /* wait on sends */ if (nsends) { send_status = (MPI_Status*)PetscMalloc(nsends*sizeof(MPI_Status));CHKPTRQ(send_status); ierr = MPI_Waitall(nsends,send_waits,send_status);CHKERRQ(ierr); ierr = PetscFree(send_status);CHKERRQ(ierr); } ierr = PetscFree(send_waits);CHKERRQ(ierr); ierr = PetscFree(svalues);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatMult_MPIDense" int MatMult_MPIDense(Mat mat,Vec xx,Vec yy) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr; PetscFunctionBegin; ierr = VecScatterBegin(xx,mdn->lvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = VecScatterEnd(xx,mdn->lvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = MatMult_SeqDense(mdn->A,mdn->lvec,yy);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatMultAdd_MPIDense" int MatMultAdd_MPIDense(Mat mat,Vec xx,Vec yy,Vec zz) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr; PetscFunctionBegin; ierr = VecScatterBegin(xx,mdn->lvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = VecScatterEnd(xx,mdn->lvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = MatMultAdd_SeqDense(mdn->A,mdn->lvec,yy,zz);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatMultTranspose_MPIDense" int MatMultTranspose_MPIDense(Mat A,Vec xx,Vec yy) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; int ierr; Scalar zero = 0.0; PetscFunctionBegin; ierr = VecSet(&zero,yy);CHKERRQ(ierr); ierr = MatMultTranspose_SeqDense(a->A,xx,a->lvec);CHKERRQ(ierr); ierr = VecScatterBegin(a->lvec,yy,ADD_VALUES,SCATTER_REVERSE,a->Mvctx);CHKERRQ(ierr); ierr = VecScatterEnd(a->lvec,yy,ADD_VALUES,SCATTER_REVERSE,a->Mvctx);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatMultTransposeAdd_MPIDense" int MatMultTransposeAdd_MPIDense(Mat A,Vec xx,Vec yy,Vec zz) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; int ierr; PetscFunctionBegin; ierr = VecCopy(yy,zz);CHKERRQ(ierr); ierr = MatMultTranspose_SeqDense(a->A,xx,a->lvec);CHKERRQ(ierr); ierr = VecScatterBegin(a->lvec,zz,ADD_VALUES,SCATTER_REVERSE,a->Mvctx);CHKERRQ(ierr); ierr = VecScatterEnd(a->lvec,zz,ADD_VALUES,SCATTER_REVERSE,a->Mvctx);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetDiagonal_MPIDense" int MatGetDiagonal_MPIDense(Mat A,Vec v) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; Mat_SeqDense *aloc = (Mat_SeqDense*)a->A->data; int ierr,len,i,n,m = a->m,radd; Scalar *x,zero = 0.0; PetscFunctionBegin; VecSet(&zero,v); ierr = VecGetArray(v,&x);CHKERRQ(ierr); ierr = VecGetSize(v,&n);CHKERRQ(ierr); if (n != a->M) SETERRQ(PETSC_ERR_ARG_SIZ,0,"Nonconforming mat and vec"); len = PetscMin(aloc->m,aloc->n); radd = a->rstart*m; for (i=0; iv[radd + i*m + i]; } ierr = VecRestoreArray(v,&x);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatDestroy_MPIDense" int MatDestroy_MPIDense(Mat mat) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr; PetscFunctionBegin; if (mat->mapping) { ierr = ISLocalToGlobalMappingDestroy(mat->mapping);CHKERRQ(ierr); } if (mat->bmapping) { ierr = ISLocalToGlobalMappingDestroy(mat->bmapping);CHKERRQ(ierr); } #if defined(PETSC_USE_LOG) PLogObjectState((PetscObject)mat,"Rows=%d, Cols=%d",mdn->M,mdn->N); #endif ierr = MatStashDestroy_Private(&mat->stash);CHKERRQ(ierr); ierr = PetscFree(mdn->rowners);CHKERRQ(ierr); ierr = MatDestroy(mdn->A);CHKERRQ(ierr); if (mdn->lvec) VecDestroy(mdn->lvec); if (mdn->Mvctx) VecScatterDestroy(mdn->Mvctx); if (mdn->factor) { if (mdn->factor->temp) {ierr = PetscFree(mdn->factor->temp);CHKERRQ(ierr);} if (mdn->factor->tag) {ierr = PetscFree(mdn->factor->tag);CHKERRQ(ierr);} if (mdn->factor->pivots) {ierr = PetscFree(mdn->factor->pivots);CHKERRQ(ierr);} ierr = PetscFree(mdn->factor);CHKERRQ(ierr); } ierr = PetscFree(mdn);CHKERRQ(ierr); if (mat->rmap) { ierr = MapDestroy(mat->rmap);CHKERRQ(ierr); } if (mat->cmap) { ierr = MapDestroy(mat->cmap);CHKERRQ(ierr); } PLogObjectDestroy(mat); PetscHeaderDestroy(mat); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatView_MPIDense_Binary" static int MatView_MPIDense_Binary(Mat mat,Viewer viewer) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr; PetscFunctionBegin; if (mdn->size == 1) { ierr = MatView(mdn->A,viewer);CHKERRQ(ierr); } else SETERRQ(PETSC_ERR_SUP,0,"Only uniprocessor output supported"); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatView_MPIDense_ASCIIorDraworSocket" static int MatView_MPIDense_ASCIIorDraworSocket(Mat mat,Viewer viewer) { Mat_MPIDense *mdn = (Mat_MPIDense*)mat->data; int ierr,format,size = mdn->size,rank = mdn->rank; ViewerType vtype; PetscTruth isascii,isdraw; PetscFunctionBegin; ierr = PetscTypeCompare((PetscObject)viewer,ASCII_VIEWER,&isascii);CHKERRQ(ierr); ierr = PetscTypeCompare((PetscObject)viewer,DRAW_VIEWER,&isdraw);CHKERRQ(ierr); if (isascii) { ierr = ViewerGetType(viewer,&vtype);CHKERRQ(ierr); ierr = ViewerGetFormat(viewer,&format);CHKERRQ(ierr); if (format == VIEWER_FORMAT_ASCII_INFO_LONG) { MatInfo info; ierr = MatGetInfo(mat,MAT_LOCAL,&info);CHKERRQ(ierr); ierr = ViewerASCIISynchronizedPrintf(viewer," [%d] local rows %d nz %d nz alloced %d mem %d \n",rank,mdn->m, (int)info.nz_used,(int)info.nz_allocated,(int)info.memory);CHKERRQ(ierr); ierr = ViewerFlush(viewer);CHKERRQ(ierr); ierr = VecScatterView(mdn->Mvctx,viewer);CHKERRQ(ierr); PetscFunctionReturn(0); } else if (format == VIEWER_FORMAT_ASCII_INFO) { PetscFunctionReturn(0); } } else if (isdraw) { Draw draw; PetscTruth isnull; ierr = ViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); ierr = DrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0); } if (size == 1) { ierr = MatView(mdn->A,viewer);CHKERRQ(ierr); } else { /* assemble the entire matrix onto first processor. */ Mat A; int M = mdn->M,N = mdn->N,m,row,i,nz,*cols; Scalar *vals; Mat_SeqDense *Amdn = (Mat_SeqDense*)mdn->A->data; if (!rank) { ierr = MatCreateMPIDense(mat->comm,M,N,M,N,PETSC_NULL,&A);CHKERRQ(ierr); } else { ierr = MatCreateMPIDense(mat->comm,0,0,M,N,PETSC_NULL,&A);CHKERRQ(ierr); } PLogObjectParent(mat,A); /* Copy the matrix ... This isn't the most efficient means, but it's quick for now */ row = mdn->rstart; m = Amdn->m; for (i=0; idata))->A,sviewer);CHKERRQ(ierr); ierr = ViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); } ierr = ViewerFlush(viewer);CHKERRQ(ierr); ierr = MatDestroy(A);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatView_MPIDense" int MatView_MPIDense(Mat mat,Viewer viewer) { int ierr; PetscTruth isascii,isbinary,isdraw,issocket; PetscFunctionBegin; ierr = PetscTypeCompare((PetscObject)viewer,ASCII_VIEWER,&isascii);CHKERRQ(ierr); ierr = PetscTypeCompare((PetscObject)viewer,BINARY_VIEWER,&isbinary);CHKERRQ(ierr); ierr = PetscTypeCompare((PetscObject)viewer,SOCKET_VIEWER,&issocket);CHKERRQ(ierr); ierr = PetscTypeCompare((PetscObject)viewer,DRAW_VIEWER,&isdraw);CHKERRQ(ierr); if (isascii || issocket || isdraw) { ierr = MatView_MPIDense_ASCIIorDraworSocket(mat,viewer);CHKERRQ(ierr); } else if (isbinary) { ierr = MatView_MPIDense_Binary(mat,viewer);CHKERRQ(ierr); } else { SETERRQ1(1,1,"Viewer type %s not supported by MPI dense matrix",((PetscObject)viewer)->type_name); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetInfo_MPIDense" int MatGetInfo_MPIDense(Mat A,MatInfoType flag,MatInfo *info) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data; Mat mdn = mat->A; int ierr; PetscReal isend[5],irecv[5]; PetscFunctionBegin; info->rows_global = (double)mat->M; info->columns_global = (double)mat->N; info->rows_local = (double)mat->m; info->columns_local = (double)mat->N; info->block_size = 1.0; ierr = MatGetInfo(mdn,MAT_LOCAL,info);CHKERRQ(ierr); isend[0] = info->nz_used; isend[1] = info->nz_allocated; isend[2] = info->nz_unneeded; isend[3] = info->memory; isend[4] = info->mallocs; if (flag == MAT_LOCAL) { info->nz_used = isend[0]; info->nz_allocated = isend[1]; info->nz_unneeded = isend[2]; info->memory = isend[3]; info->mallocs = isend[4]; } else if (flag == MAT_GLOBAL_MAX) { ierr = MPI_Allreduce(isend,irecv,5,MPI_DOUBLE,MPI_MAX,A->comm);CHKERRQ(ierr); info->nz_used = irecv[0]; info->nz_allocated = irecv[1]; info->nz_unneeded = irecv[2]; info->memory = irecv[3]; info->mallocs = irecv[4]; } else if (flag == MAT_GLOBAL_SUM) { ierr = MPI_Allreduce(isend,irecv,5,MPI_DOUBLE,MPI_SUM,A->comm);CHKERRQ(ierr); info->nz_used = irecv[0]; info->nz_allocated = irecv[1]; info->nz_unneeded = irecv[2]; info->memory = irecv[3]; info->mallocs = irecv[4]; } info->fill_ratio_given = 0; /* no parallel LU/ILU/Cholesky */ info->fill_ratio_needed = 0; info->factor_mallocs = 0; PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatSetOption_MPIDense" int MatSetOption_MPIDense(Mat A,MatOption op) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; PetscFunctionBegin; if (op == MAT_NO_NEW_NONZERO_LOCATIONS || op == MAT_YES_NEW_NONZERO_LOCATIONS || op == MAT_NEW_NONZERO_LOCATION_ERR || op == MAT_NEW_NONZERO_ALLOCATION_ERR || op == MAT_COLUMNS_SORTED || op == MAT_COLUMNS_UNSORTED) { MatSetOption(a->A,op); } else if (op == MAT_ROW_ORIENTED) { a->roworiented = 1; MatSetOption(a->A,op); } else if (op == MAT_ROWS_SORTED || op == MAT_ROWS_UNSORTED || op == MAT_SYMMETRIC || op == MAT_STRUCTURALLY_SYMMETRIC || op == MAT_YES_NEW_DIAGONALS || op == MAT_USE_HASH_TABLE) { PLogInfo(A,"MatSetOption_MPIDense:Option ignored\n"); } else if (op == MAT_COLUMN_ORIENTED) { a->roworiented = 0; MatSetOption(a->A,op); } else if (op == MAT_IGNORE_OFF_PROC_ENTRIES) { a->donotstash = 1; } else if (op == MAT_NO_NEW_DIAGONALS) { SETERRQ(PETSC_ERR_SUP,0,"MAT_NO_NEW_DIAGONALS"); } else { SETERRQ(PETSC_ERR_SUP,0,"unknown option"); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetSize_MPIDense" int MatGetSize_MPIDense(Mat A,int *m,int *n) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data; PetscFunctionBegin; if (m) *m = mat->M; if (n) *n = mat->N; PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetLocalSize_MPIDense" int MatGetLocalSize_MPIDense(Mat A,int *m,int *n) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data; PetscFunctionBegin; *m = mat->m; *n = mat->N; PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetOwnershipRange_MPIDense" int MatGetOwnershipRange_MPIDense(Mat A,int *m,int *n) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data; PetscFunctionBegin; if (m) *m = mat->rstart; if (n) *n = mat->rend; PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatGetRow_MPIDense" int MatGetRow_MPIDense(Mat A,int row,int *nz,int **idx,Scalar **v) { Mat_MPIDense *mat = (Mat_MPIDense*)A->data; int lrow,rstart = mat->rstart,rend = mat->rend,ierr; PetscFunctionBegin; if (row < rstart || row >= rend) SETERRQ(PETSC_ERR_SUP,0,"only local rows") lrow = row - rstart; ierr = MatGetRow(mat->A,lrow,nz,idx,v);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatRestoreRow_MPIDense" int MatRestoreRow_MPIDense(Mat mat,int row,int *nz,int **idx,Scalar **v) { int ierr; PetscFunctionBegin; if (idx) {ierr = PetscFree(*idx);CHKERRQ(ierr);} if (v) {ierr = PetscFree(*v);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatDiagonalScale_MPIDense" int MatDiagonalScale_MPIDense(Mat A,Vec ll,Vec rr) { Mat_MPIDense *mdn = (Mat_MPIDense*)A->data; Mat_SeqDense *mat = (Mat_SeqDense*)mdn->A->data; Scalar *l,*r,x,*v; int ierr,i,j,s2a,s3a,s2,s3,m=mat->m,n=mat->n; PetscFunctionBegin; ierr = MatGetLocalSize(A,&s2,&s3);CHKERRQ(ierr); if (ll) { ierr = VecGetLocalSize(ll,&s2a);CHKERRQ(ierr); if (s2a != s2) SETERRQ(PETSC_ERR_ARG_SIZ,0,"Left scaling vector non-conforming local size"); ierr = VecGetArray(ll,&l);CHKERRQ(ierr); for (i=0; iv + i; for (j=0; jlvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = VecScatterEnd(rr,mdn->lvec,INSERT_VALUES,SCATTER_FORWARD,mdn->Mvctx);CHKERRQ(ierr); ierr = VecGetArray(mdn->lvec,&r);CHKERRQ(ierr); for (i=0; iv + i*m; for (j=0; jlvec,&r);CHKERRQ(ierr); PLogFlops(n*m); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatNorm_MPIDense" int MatNorm_MPIDense(Mat A,NormType type,PetscReal *norm) { Mat_MPIDense *mdn = (Mat_MPIDense*)A->data; Mat_SeqDense *mat = (Mat_SeqDense*)mdn->A->data; int ierr,i,j; PetscReal sum = 0.0; Scalar *v = mat->v; PetscFunctionBegin; if (mdn->size == 1) { ierr = MatNorm(mdn->A,type,norm);CHKERRQ(ierr); } else { if (type == NORM_FROBENIUS) { for (i=0; in*mat->m; i++) { #if defined(PETSC_USE_COMPLEX) sum += PetscRealPart(PetscConj(*v)*(*v)); v++; #else sum += (*v)*(*v); v++; #endif } ierr = MPI_Allreduce(&sum,norm,1,MPI_DOUBLE,MPI_SUM,A->comm);CHKERRQ(ierr); *norm = sqrt(*norm); PLogFlops(2*mat->n*mat->m); } else if (type == NORM_1) { PetscReal *tmp,*tmp2; tmp = (PetscReal*)PetscMalloc(2*mdn->N*sizeof(PetscReal));CHKPTRQ(tmp); tmp2 = tmp + mdn->N; ierr = PetscMemzero(tmp,2*mdn->N*sizeof(PetscReal));CHKERRQ(ierr); *norm = 0.0; v = mat->v; for (j=0; jn; j++) { for (i=0; im; i++) { tmp[j] += PetscAbsScalar(*v); v++; } } ierr = MPI_Allreduce(tmp,tmp2,mdn->N,MPI_DOUBLE,MPI_SUM,A->comm);CHKERRQ(ierr); for (j=0; jN; j++) { if (tmp2[j] > *norm) *norm = tmp2[j]; } ierr = PetscFree(tmp);CHKERRQ(ierr); PLogFlops(mat->n*mat->m); } else if (type == NORM_INFINITY) { /* max row norm */ PetscReal ntemp; ierr = MatNorm(mdn->A,type,&ntemp);CHKERRQ(ierr); ierr = MPI_Allreduce(&ntemp,norm,1,MPI_DOUBLE,MPI_MAX,A->comm);CHKERRQ(ierr); } else { SETERRQ(PETSC_ERR_SUP,0,"No support for two norm"); } } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatTranspose_MPIDense" int MatTranspose_MPIDense(Mat A,Mat *matout) { Mat_MPIDense *a = (Mat_MPIDense*)A->data; Mat_SeqDense *Aloc = (Mat_SeqDense*)a->A->data; Mat B; int M = a->M,N = a->N,m,n,*rwork,rstart = a->rstart; int j,i,ierr; Scalar *v; PetscFunctionBegin; if (!matout && M != N) { SETERRQ(PETSC_ERR_SUP,0,"Supports square matrix only in-place"); } ierr = MatCreateMPIDense(A->comm,PETSC_DECIDE,PETSC_DECIDE,N,M,PETSC_NULL,&B);CHKERRQ(ierr); m = Aloc->m; n = Aloc->n; v = Aloc->v; rwork = (int*)PetscMalloc(n*sizeof(int));CHKPTRQ(rwork); for (j=0; jrowners);CHKERRQ(ierr); ierr = MatDestroy(a->A);CHKERRQ(ierr); if (a->lvec) VecDestroy(a->lvec); if (a->Mvctx) VecScatterDestroy(a->Mvctx); ierr = PetscFree(a);CHKERRQ(ierr); /* This is horrible, horrible code. We need to keep the A pointers for the bops and ops but copy everything else from C. */ Abops = A->bops; Aops = A->ops; ierr = PetscMemcpy(A,B,sizeof(struct _p_Mat));CHKERRQ(ierr); A->bops = Abops; A->ops = Aops; PetscHeaderDestroy(B); } PetscFunctionReturn(0); } #include "pinclude/blaslapack.h" #undef __FUNC__ #define __FUNC__ /**/"MatScale_MPIDense" int MatScale_MPIDense(Scalar *alpha,Mat inA) { Mat_MPIDense *A = (Mat_MPIDense*)inA->data; Mat_SeqDense *a = (Mat_SeqDense*)A->A->data; int one = 1,nz; PetscFunctionBegin; nz = a->m*a->n; BLscal_(&nz,alpha,a->v,&one); PLogFlops(nz); PetscFunctionReturn(0); } static int MatDuplicate_MPIDense(Mat,MatDuplicateOption,Mat *); extern int MatGetSubMatrices_MPIDense(Mat,int,IS *,IS *,MatReuse,Mat **); /* -------------------------------------------------------------------*/ static struct _MatOps MatOps_Values = {MatSetValues_MPIDense, MatGetRow_MPIDense, MatRestoreRow_MPIDense, MatMult_MPIDense, MatMultAdd_MPIDense, MatMultTranspose_MPIDense, MatMultTransposeAdd_MPIDense, 0, 0, 0, 0, 0, 0, 0, MatTranspose_MPIDense, MatGetInfo_MPIDense,0, MatGetDiagonal_MPIDense, MatDiagonalScale_MPIDense, MatNorm_MPIDense, MatAssemblyBegin_MPIDense, MatAssemblyEnd_MPIDense, 0, MatSetOption_MPIDense, MatZeroEntries_MPIDense, MatZeroRows_MPIDense, 0, 0, 0, 0, MatGetSize_MPIDense, MatGetLocalSize_MPIDense, MatGetOwnershipRange_MPIDense, 0, 0, MatGetArray_MPIDense, MatRestoreArray_MPIDense, MatDuplicate_MPIDense, 0, 0, 0, 0, 0, MatGetSubMatrices_MPIDense, 0, MatGetValues_MPIDense, 0, 0, MatScale_MPIDense, 0, 0, 0, MatGetBlockSize_MPIDense, 0, 0, 0, 0, 0, 0, 0, 0, 0, MatGetSubMatrix_MPIDense, 0, 0, MatGetMaps_Petsc}; #undef __FUNC__ #define __FUNC__ /**/"MatCreateMPIDense" /*@C MatCreateMPIDense - Creates a sparse parallel matrix in dense format. Collective on MPI_Comm Input Parameters: + comm - MPI communicator . m - number of local rows (or PETSC_DECIDE to have calculated if M is given) . n - number of local columns (or PETSC_DECIDE to have calculated if N is given) . M - number of global rows (or PETSC_DECIDE to have calculated if m is given) . N - number of global columns (or PETSC_DECIDE to have calculated if n is given) - data - optional location of matrix data. Set data=PETSC_NULL for PETSc to control all matrix memory allocation. Output Parameter: . A - the matrix Notes: The dense format is fully compatible with standard Fortran 77 storage by columns. The data input variable is intended primarily for Fortran programmers who wish to allocate their own matrix memory space. Most users should set data=PETSC_NULL. The user MUST specify either the local or global matrix dimensions (possibly both). Level: intermediate .keywords: matrix,dense, parallel .seealso: MatCreate(), MatCreateSeqDense(), MatSetValues() @*/ int MatCreateMPIDense(MPI_Comm comm,int m,int n,int M,int N,Scalar *data,Mat *A) { Mat mat; Mat_MPIDense *a; int ierr,i; PetscTruth flg; PetscFunctionBegin; /* Note: For now, when data is specified above, this assumes the user correctly allocates the local dense storage space. We should add error checking. */ *A = 0; PetscHeaderCreate(mat,_p_Mat,struct _MatOps,MAT_COOKIE,MATMPIDENSE,"Mat",comm,MatDestroy,MatView); PLogObjectCreate(mat); mat->data = (void*)(a = PetscNew(Mat_MPIDense));CHKPTRQ(a); ierr = PetscMemcpy(mat->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); mat->ops->destroy = MatDestroy_MPIDense; mat->ops->view = MatView_MPIDense; mat->factor = 0; mat->mapping = 0; a->factor = 0; mat->insertmode = NOT_SET_VALUES; ierr = MPI_Comm_rank(comm,&a->rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm,&a->size);CHKERRQ(ierr); ierr = PetscSplitOwnership(comm,&m,&M);CHKERRQ(ierr); ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); a->nvec = n; /* each row stores all columns */ a->N = mat->N = N; a->M = mat->M = M; a->m = mat->m = m; a->n = mat->n = N; /* NOTE: n == N */ /* the information in the maps duplicates the information computed below, eventually we should remove the duplicate information that is not contained in the maps */ ierr = MapCreateMPI(comm,m,M,&mat->rmap);CHKERRQ(ierr); ierr = MapCreateMPI(comm,n,N,&mat->cmap);CHKERRQ(ierr); /* build local table of row and column ownerships */ a->rowners = (int*)PetscMalloc(2*(a->size+2)*sizeof(int));CHKPTRQ(a->rowners); a->cowners = a->rowners + a->size + 1; PLogObjectMemory(mat,2*(a->size+2)*sizeof(int)+sizeof(struct _p_Mat)+sizeof(Mat_MPIDense)); ierr = MPI_Allgather(&m,1,MPI_INT,a->rowners+1,1,MPI_INT,comm);CHKERRQ(ierr); a->rowners[0] = 0; for (i=2; i<=a->size; i++) { a->rowners[i] += a->rowners[i-1]; } a->rstart = a->rowners[a->rank]; a->rend = a->rowners[a->rank+1]; ierr = MPI_Allgather(&n,1,MPI_INT,a->cowners+1,1,MPI_INT,comm);CHKERRQ(ierr); a->cowners[0] = 0; for (i=2; i<=a->size; i++) { a->cowners[i] += a->cowners[i-1]; } ierr = MatCreateSeqDense(PETSC_COMM_SELF,m,N,data,&a->A);CHKERRQ(ierr); PLogObjectParent(mat,a->A); /* build cache for off array entries formed */ a->donotstash = 0; ierr = MatStashCreate_Private(comm,1,&mat->stash);CHKERRQ(ierr); /* stuff used for matrix vector multiply */ a->lvec = 0; a->Mvctx = 0; a->roworiented = 1; ierr = PetscObjectComposeFunctionDynamic((PetscObject)mat,"MatGetDiagonalBlock_C", "MatGetDiagonalBlock_MPIDense", (void*)MatGetDiagonalBlock_MPIDense);CHKERRQ(ierr); *A = mat; ierr = OptionsHasName(PETSC_NULL,"-help",&flg);CHKERRQ(ierr); if (flg) { ierr = MatPrintHelp(mat);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNC__ #define __FUNC__ /**/"MatDuplicate_MPIDense" static int MatDuplicate_MPIDense(Mat A,MatDuplicateOption cpvalues,Mat *newmat) { Mat mat; Mat_MPIDense *a,*oldmat = (Mat_MPIDense*)A->data; int ierr; FactorCtx *factor; PetscFunctionBegin; *newmat = 0; PetscHeaderCreate(mat,_p_Mat,struct _MatOps,MAT_COOKIE,MATMPIDENSE,"Mat",A->comm,MatDestroy,MatView); PLogObjectCreate(mat); mat->data = (void*)(a = PetscNew(Mat_MPIDense));CHKPTRQ(a); ierr = PetscMemcpy(mat->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); mat->ops->destroy = MatDestroy_MPIDense; mat->ops->view = MatView_MPIDense; mat->factor = A->factor; mat->assembled = PETSC_TRUE; a->m = mat->m = oldmat->m; a->n = mat->n = oldmat->n; a->M = mat->M = oldmat->M; a->N = mat->N = oldmat->N; if (oldmat->factor) { a->factor = (FactorCtx*)(factor = PetscNew(FactorCtx));CHKPTRQ(factor); /* copy factor contents ... add this code! */ } else a->factor = 0; a->rstart = oldmat->rstart; a->rend = oldmat->rend; a->size = oldmat->size; a->rank = oldmat->rank; mat->insertmode = NOT_SET_VALUES; a->donotstash = oldmat->donotstash; a->rowners = (int*)PetscMalloc((a->size+1)*sizeof(int));CHKPTRQ(a->rowners); PLogObjectMemory(mat,(a->size+1)*sizeof(int)+sizeof(struct _p_Mat)+sizeof(Mat_MPIDense)); ierr = PetscMemcpy(a->rowners,oldmat->rowners,(a->size+1)*sizeof(int));CHKERRQ(ierr); ierr = MatStashCreate_Private(A->comm,1,&mat->stash);CHKERRQ(ierr); ierr = MatSetUpMultiply_MPIDense(mat);CHKERRQ(ierr); ierr = MatDuplicate(oldmat->A,cpvalues,&a->A);CHKERRQ(ierr); PLogObjectParent(mat,a->A); *newmat = mat; PetscFunctionReturn(0); } #include "sys.h" #undef __FUNC__ #define __FUNC__ /**/"MatLoad_MPIDense_DenseInFile" int MatLoad_MPIDense_DenseInFile(MPI_Comm comm,int fd,int M,int N,Mat *newmat) { int *rowners,i,size,rank,m,ierr,nz,j; Scalar *array,*vals,*vals_ptr; MPI_Status status; PetscFunctionBegin; ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); /* determine ownership of all rows */ m = M/size + ((M % size) > rank); rowners = (int*)PetscMalloc((size+2)*sizeof(int));CHKPTRQ(rowners); ierr = MPI_Allgather(&m,1,MPI_INT,rowners+1,1,MPI_INT,comm);CHKERRQ(ierr); rowners[0] = 0; for (i=2; i<=size; i++) { rowners[i] += rowners[i-1]; } ierr = MatCreateMPIDense(comm,m,PETSC_DECIDE,M,N,PETSC_NULL,newmat);CHKERRQ(ierr); ierr = MatGetArray(*newmat,&array);CHKERRQ(ierr); if (!rank) { vals = (Scalar*)PetscMalloc(m*N*sizeof(Scalar));CHKPTRQ(vals); /* read in my part of the matrix numerical values */ ierr = PetscBinaryRead(fd,vals,m*N,PETSC_SCALAR);CHKERRQ(ierr); /* insert into matrix-by row (this is why cannot directly read into array */ vals_ptr = vals; for (i=0; itag,comm);CHKERRQ(ierr); } } else { /* receive numeric values */ vals = (Scalar*)PetscMalloc(m*N*sizeof(Scalar));CHKPTRQ(vals); /* receive message of values*/ ierr = MPI_Recv(vals,m*N,MPIU_SCALAR,0,(*newmat)->tag,comm,&status);CHKERRQ(ierr); /* insert into matrix-by row (this is why cannot directly read into array */ vals_ptr = vals; for (i=0; i*/"MatLoad_MPIDense" int MatLoad_MPIDense(Viewer viewer,MatType type,Mat *newmat) { Mat A; Scalar *vals,*svals; MPI_Comm comm = ((PetscObject)viewer)->comm; MPI_Status status; int header[4],rank,size,*rowlengths = 0,M,N,m,*rowners,maxnz,*cols; int *ourlens,*sndcounts = 0,*procsnz = 0,*offlens,jj,*mycols,*smycols; int tag = ((PetscObject)viewer)->tag; int i,nz,ierr,j,rstart,rend,fd; PetscFunctionBegin; ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); if (!rank) { ierr = ViewerBinaryGetDescriptor(viewer,&fd);CHKERRQ(ierr); ierr = PetscBinaryRead(fd,(char *)header,4,PETSC_INT);CHKERRQ(ierr); if (header[0] != MAT_COOKIE) SETERRQ(PETSC_ERR_FILE_UNEXPECTED,0,"not matrix object"); } ierr = MPI_Bcast(header+1,3,MPI_INT,0,comm);CHKERRQ(ierr); M = header[1]; N = header[2]; nz = header[3]; /* Handle case where matrix is stored on disk as a dense matrix */ if (nz == MATRIX_BINARY_FORMAT_DENSE) { ierr = MatLoad_MPIDense_DenseInFile(comm,fd,M,N,newmat);CHKERRQ(ierr); PetscFunctionReturn(0); } /* determine ownership of all rows */ m = M/size + ((M % size) > rank); rowners = (int*)PetscMalloc((size+2)*sizeof(int));CHKPTRQ(rowners); ierr = MPI_Allgather(&m,1,MPI_INT,rowners+1,1,MPI_INT,comm);CHKERRQ(ierr); rowners[0] = 0; for (i=2; i<=size; i++) { rowners[i] += rowners[i-1]; } rstart = rowners[rank]; rend = rowners[rank+1]; /* distribute row lengths to all processors */ ourlens = (int*)PetscMalloc(2*(rend-rstart)*sizeof(int));CHKPTRQ(ourlens); offlens = ourlens + (rend-rstart); if (!rank) { rowlengths = (int*)PetscMalloc(M*sizeof(int));CHKPTRQ(rowlengths); ierr = PetscBinaryRead(fd,rowlengths,M,PETSC_INT);CHKERRQ(ierr); sndcounts = (int*)PetscMalloc(size*sizeof(int));CHKPTRQ(sndcounts); for (i=0; i= rend) offlens[i]++; jj++; } } /* create our matrix */ for (i=0; itag,comm);CHKERRQ(ierr); } ierr = PetscFree(procsnz);CHKERRQ(ierr); } else { /* receive numeric values */ vals = (Scalar*)PetscMalloc(nz*sizeof(Scalar));CHKPTRQ(vals); /* receive message of values*/ ierr = MPI_Recv(vals,nz,MPIU_SCALAR,0,A->tag,comm,&status);CHKERRQ(ierr); ierr = MPI_Get_count(&status,MPIU_SCALAR,&maxnz);CHKERRQ(ierr); if (maxnz != nz) SETERRQ(PETSC_ERR_FILE_UNEXPECTED,0,"something is wrong with file"); /* insert into matrix */ jj = rstart; smycols = mycols; svals = vals; for (i=0; i