static char help[] = "Tests the use of interface functions for MATIS matrices.\n\ This example tests: MatZeroRows(), MatZeroRowsLocal(), MatView(), MatDuplicate(),\n\ MatCopy(), MatCreateSubMatrix(), MatGetLocalSubMatrix(), MatAXPY(), MatShift()\n\ MatDiagonalSet(), MatTranspose() and MatPtAP(). It also tests some\n\ conversion routines.\n"; #include PetscErrorCode TestMatZeroRows(Mat,Mat,PetscBool,IS,PetscScalar); PetscErrorCode CheckMat(Mat,Mat,PetscBool,const char*); int main(int argc,char **args) { Mat A,B,A2,B2,T; Mat Aee,Aeo,Aoe,Aoo; Mat *mats; Vec x,y; MatInfo info; ISLocalToGlobalMapping cmap,rmap; IS is,is2,reven,rodd,ceven,codd; IS *rows,*cols; MatType lmtype; PetscScalar diag = 2.; PetscInt n,m,i,lm,ln; PetscInt rst,ren,cst,cen,nr,nc; PetscMPIInt rank,size; PetscBool testT,squaretest,isaij; PetscBool permute = PETSC_FALSE, negmap = PETSC_FALSE, repmap = PETSC_FALSE; PetscBool diffmap = PETSC_TRUE, symmetric = PETSC_FALSE, issymmetric; PetscErrorCode ierr; PetscCall(PetscInitialize(&argc,&args,(char*)0,help)); PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank)); PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size)); m = n = 2*size; PetscCall(PetscOptionsGetBool(NULL,NULL,"-symmetric",&symmetric,NULL)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-m",&m,NULL)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL)); PetscCall(PetscOptionsGetBool(NULL,NULL,"-negmap",&negmap,NULL)); PetscCall(PetscOptionsGetBool(NULL,NULL,"-repmap",&repmap,NULL)); PetscCall(PetscOptionsGetBool(NULL,NULL,"-permmap",&permute,NULL)); PetscCall(PetscOptionsGetBool(NULL,NULL,"-diffmap",&diffmap,NULL)); PetscCheck(size == 1 || m >= 4,PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Number of rows should be larger or equal 4 for parallel runs"); PetscCheck(size != 1 || m >= 2,PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Number of rows should be larger or equal 2 for uniprocessor runs"); PetscCheck(n >= 2,PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Number of cols should be larger or equal 2"); /* create a MATIS matrix */ PetscCall(MatCreate(PETSC_COMM_WORLD,&A)); PetscCall(MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,m,n)); PetscCall(MatSetType(A,MATIS)); PetscCall(MatSetFromOptions(A)); if (!negmap && !repmap) { /* This is not the proper setting for MATIS for finite elements, it is just used to test the routines Here we use a one-to-one correspondence between local row/column spaces and global row/column spaces Equivalent to passing NULL for the mapping */ PetscCall(ISCreateStride(PETSC_COMM_WORLD,n,0,1,&is)); } else if (negmap && !repmap) { /* non repeated but with negative indices */ PetscCall(ISCreateStride(PETSC_COMM_WORLD,n+2,-2,1,&is)); } else if (!negmap && repmap) { /* non negative but repeated indices */ IS isl[2]; PetscCall(ISCreateStride(PETSC_COMM_WORLD,n,0,1,&isl[0])); PetscCall(ISCreateStride(PETSC_COMM_WORLD,n,n-1,-1,&isl[1])); PetscCall(ISConcatenate(PETSC_COMM_WORLD,2,isl,&is)); PetscCall(ISDestroy(&isl[0])); PetscCall(ISDestroy(&isl[1])); } else { /* negative and repeated indices */ IS isl[2]; PetscCall(ISCreateStride(PETSC_COMM_WORLD,n+1,-1,1,&isl[0])); PetscCall(ISCreateStride(PETSC_COMM_WORLD,n+1,n-1,-1,&isl[1])); PetscCall(ISConcatenate(PETSC_COMM_WORLD,2,isl,&is)); PetscCall(ISDestroy(&isl[0])); PetscCall(ISDestroy(&isl[1])); } PetscCall(ISLocalToGlobalMappingCreateIS(is,&cmap)); PetscCall(ISDestroy(&is)); if (m != n || diffmap) { PetscCall(ISCreateStride(PETSC_COMM_WORLD,m,permute ? m-1 : 0,permute ? -1 : 1,&is)); PetscCall(ISLocalToGlobalMappingCreateIS(is,&rmap)); PetscCall(ISDestroy(&is)); } else { PetscCall(PetscObjectReference((PetscObject)cmap)); rmap = cmap; } PetscCall(MatSetLocalToGlobalMapping(A,rmap,cmap)); PetscCall(MatISStoreL2L(A,PETSC_FALSE)); PetscCall(MatISSetPreallocation(A,3,NULL,3,NULL)); PetscCall(MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,(PetscBool)!(repmap || negmap))); /* I do not want to precompute the pattern */ PetscCall(ISLocalToGlobalMappingGetSize(rmap,&lm)); PetscCall(ISLocalToGlobalMappingGetSize(cmap,&ln)); for (i=0; i 3) { PetscCall(ISCreateStride(PETSC_COMM_WORLD,1,3,1,&is2)); } else { PetscCall(ISCreateStride(PETSC_COMM_WORLD,0,0,1,&is2)); } } else if (rank == 2 && n > 4) { PetscCall(ISCreateStride(PETSC_COMM_WORLD,0,0,1,&is)); PetscCall(ISCreateStride(PETSC_COMM_WORLD,n-4,4,1,&is2)); } else { PetscCall(ISCreateStride(PETSC_COMM_WORLD,0,0,1,&is)); PetscCall(ISCreateStride(PETSC_COMM_WORLD,0,0,1,&is2)); } PetscCall(MatCreateSubMatrix(A,is,is,MAT_INITIAL_MATRIX,&A2)); PetscCall(MatCreateSubMatrix(B,is,is,MAT_INITIAL_MATRIX,&B2)); PetscCall(CheckMat(A2,B2,PETSC_TRUE,"first MatCreateSubMatrix")); PetscCall(MatCreateSubMatrix(A,is,is,MAT_REUSE_MATRIX,&A2)); PetscCall(MatCreateSubMatrix(B,is,is,MAT_REUSE_MATRIX,&B2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"reuse MatCreateSubMatrix")); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); if (!issymmetric) { PetscCall(MatCreateSubMatrix(A,is,is2,MAT_INITIAL_MATRIX,&A2)); PetscCall(MatCreateSubMatrix(B,is,is2,MAT_INITIAL_MATRIX,&B2)); PetscCall(MatCreateSubMatrix(A,is,is2,MAT_REUSE_MATRIX,&A2)); PetscCall(MatCreateSubMatrix(B,is,is2,MAT_REUSE_MATRIX,&B2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"second MatCreateSubMatrix")); } PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); PetscCall(ISDestroy(&is)); PetscCall(ISDestroy(&is2)); /* Create an IS required by MatZeroRows(): just rank zero provides the rows to be eliminated */ if (size > 1) { if (rank == 0) { PetscInt st,len; st = (m+1)/2; len = PetscMin(m/2,PetscMax(m-(m+1)/2-1,0)); PetscCall(ISCreateStride(PETSC_COMM_WORLD,len,st,1,&is)); } else { PetscCall(ISCreateStride(PETSC_COMM_WORLD,0,0,1,&is)); } } else { PetscCall(ISCreateStride(PETSC_COMM_WORLD,1,0,1,&is)); } if (squaretest) { /* tests for square matrices only, with same maps for rows and columns */ /* test MatDiagonalSet */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatDiagonalSet\n")); PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&B2)); PetscCall(MatCreateVecs(A,NULL,&x)); PetscCall(VecSetRandom(x,NULL)); PetscCall(MatDiagonalSet(A2,x,INSERT_VALUES)); PetscCall(MatDiagonalSet(B2,x,INSERT_VALUES)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatDiagonalSet")); PetscCall(VecDestroy(&x)); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); /* test MatShift (MatShift_IS internally uses MatDiagonalSet_IS with ADD_VALUES) */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatShift\n")); PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&B2)); PetscCall(MatShift(A2,2.0)); PetscCall(MatShift(B2,2.0)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatShift")); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); /* nonzero diag value is supported for square matrices only */ PetscCall(TestMatZeroRows(A,B,PETSC_TRUE,is,diag)); } PetscCall(TestMatZeroRows(A,B,squaretest,is,0.0)); PetscCall(ISDestroy(&is)); /* test MatTranspose */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatTranspose\n")); PetscCall(MatTranspose(A,MAT_INITIAL_MATRIX,&A2)); PetscCall(MatTranspose(B,MAT_INITIAL_MATRIX,&B2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"initial matrix MatTranspose")); PetscCall(MatTranspose(A,MAT_REUSE_MATRIX,&A2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"reuse matrix (not in place) MatTranspose")); PetscCall(MatDestroy(&A2)); PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatTranspose(A2,MAT_INPLACE_MATRIX,&A2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"reuse matrix (in place) MatTranspose")); PetscCall(MatDestroy(&A2)); PetscCall(MatTranspose(A,MAT_INITIAL_MATRIX,&A2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"reuse matrix (different type) MatTranspose")); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); /* test MatISFixLocalEmpty */ if (isaij) { PetscInt r[2]; r[0] = 0; r[1] = PetscMin(m,n)-1; PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatISFixLocalEmpty\n")); PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatISFixLocalEmpty(A2,PETSC_TRUE)); PetscCall(MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY)); PetscCall(CheckMat(A2,B,PETSC_FALSE,"MatISFixLocalEmpty (null)")); PetscCall(MatZeroRows(A2,2,r,0.0,NULL,NULL)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&B2)); PetscCall(MatZeroRows(B2,2,r,0.0,NULL,NULL)); PetscCall(MatISFixLocalEmpty(A2,PETSC_TRUE)); PetscCall(MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatISFixLocalEmpty (rows)")); PetscCall(MatDestroy(&A2)); PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatZeroRows(A2,2,r,0.0,NULL,NULL)); PetscCall(MatTranspose(A2,MAT_INPLACE_MATRIX,&A2)); PetscCall(MatTranspose(B2,MAT_INPLACE_MATRIX,&B2)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(MatISFixLocalEmpty(A2,PETSC_TRUE)); PetscCall(MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatISFixLocalEmpty (cols)")); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); if (squaretest) { PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&A2)); PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&B2)); PetscCall(MatZeroRowsColumns(A2,2,r,0.0,NULL,NULL)); PetscCall(MatZeroRowsColumns(B2,2,r,0.0,NULL,NULL)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(MatISFixLocalEmpty(A2,PETSC_TRUE)); PetscCall(MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY)); PetscCall(MatViewFromOptions(A2,NULL,"-fixempty_view")); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatISFixLocalEmpty (rows+cols)")); PetscCall(MatDestroy(&A2)); PetscCall(MatDestroy(&B2)); } } /* test MatInvertBlockDiagonal special cases for block-diagonal matrices */ if (m == n) { ISLocalToGlobalMapping map; Mat Abd,Bbd; IS is,bis; const PetscScalar *isbd,*aijbd; PetscScalar *vals; const PetscInt *sts,*idxs; PetscInt *idxs2,diff,perm,nl,bs,st,en,in; PetscBool ok; for (diff = 0; diff < 3; diff++) { for (perm = 0; perm < 3; perm++) { for (bs = 1; bs < 4; bs++) { PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatInvertBlockDiagonal blockdiag %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n",n,diff,perm,bs)); PetscCall(PetscMalloc1(bs*bs,&vals)); PetscCall(MatGetOwnershipRanges(A,&sts)); switch (diff) { case 1: /* inverted layout by processes */ in = 1; st = sts[size - rank - 1]; en = sts[size - rank]; nl = en - st; break; case 2: /* round-robin layout */ in = size; st = rank; nl = n/size; if (rank < n%size) nl++; break; default: /* same layout */ in = 1; st = sts[rank]; en = sts[rank + 1]; nl = en - st; break; } PetscCall(ISCreateStride(PETSC_COMM_WORLD,nl,st,in,&is)); PetscCall(ISGetLocalSize(is,&nl)); PetscCall(ISGetIndices(is,&idxs)); PetscCall(PetscMalloc1(nl,&idxs2)); for (i=0;i PETSC_SMALL) ok = PETSC_FALSE; if (!ok) { PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] ERROR block %" PetscInt_FMT ", entry %" PetscInt_FMT " %" PetscInt_FMT ": %g %g\n",rank,i,b1,b2,(double)PetscAbsScalar(isbd[i*bs*bs+b1*bs + b2]),(double)PetscAbsScalar(aijbd[i*bs*bs+b1*bs + b2]))); break; } } if (!ok) break; } if (!ok) break; } PetscCall(MatDestroy(&Abd)); PetscCall(MatDestroy(&Bbd)); PetscCall(PetscFree(vals)); PetscCall(ISDestroy(&is)); PetscCall(ISDestroy(&bis)); } } } } /* free testing matrices */ PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); PetscCall(MatDestroy(&A)); PetscCall(MatDestroy(&B)); PetscCall(PetscFinalize()); return 0; } PetscErrorCode CheckMat(Mat A, Mat B, PetscBool usemult, const char* func) { Mat Bcheck; PetscReal error; PetscFunctionBeginUser; if (!usemult && B) { PetscBool hasnorm; PetscCall(MatHasOperation(B,MATOP_NORM,&hasnorm)); if (!hasnorm) usemult = PETSC_TRUE; } if (!usemult) { if (B) { MatType Btype; PetscCall(MatGetType(B,&Btype)); PetscCall(MatConvert(A,Btype,MAT_INITIAL_MATRIX,&Bcheck)); } else { PetscCall(MatConvert(A,MATAIJ,MAT_INITIAL_MATRIX,&Bcheck)); } if (B) { /* if B is present, subtract it */ PetscCall(MatAXPY(Bcheck,-1.,B,DIFFERENT_NONZERO_PATTERN)); } PetscCall(MatNorm(Bcheck,NORM_INFINITY,&error)); if (error > PETSC_SQRT_MACHINE_EPSILON) { ISLocalToGlobalMapping rl2g,cl2g; PetscCall(PetscObjectSetName((PetscObject)Bcheck,"Assembled Bcheck")); PetscCall(MatView(Bcheck,NULL)); if (B) { PetscCall(PetscObjectSetName((PetscObject)B,"Assembled AIJ")); PetscCall(MatView(B,NULL)); PetscCall(MatDestroy(&Bcheck)); PetscCall(MatConvert(A,MATAIJ,MAT_INITIAL_MATRIX,&Bcheck)); PetscCall(PetscObjectSetName((PetscObject)Bcheck,"Assembled IS")); PetscCall(MatView(Bcheck,NULL)); } PetscCall(MatDestroy(&Bcheck)); PetscCall(PetscObjectSetName((PetscObject)A,"MatIS")); PetscCall(MatView(A,NULL)); PetscCall(MatGetLocalToGlobalMapping(A,&rl2g,&cl2g)); PetscCall(ISLocalToGlobalMappingView(rl2g,NULL)); PetscCall(ISLocalToGlobalMappingView(cl2g,NULL)); SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_PLIB,"ERROR ON %s: %g",func,(double)error); } PetscCall(MatDestroy(&Bcheck)); } else { PetscBool ok,okt; PetscCall(MatMultEqual(A,B,3,&ok)); PetscCall(MatMultTransposeEqual(A,B,3,&okt)); PetscCheck(ok && okt,PETSC_COMM_WORLD,PETSC_ERR_PLIB,"ERROR ON %s: mult ok ? %d, multtranspose ok ? %d",func,ok,okt); } PetscFunctionReturn(0); } PetscErrorCode TestMatZeroRows(Mat A, Mat Afull, PetscBool squaretest, IS is, PetscScalar diag) { Mat B,Bcheck,B2 = NULL,lB; Vec x = NULL, b = NULL, b2 = NULL; ISLocalToGlobalMapping l2gr,l2gc; PetscReal error; char diagstr[16]; const PetscInt *idxs; PetscInt rst,ren,i,n,N,d; PetscMPIInt rank; PetscBool miss,haszerorows; PetscFunctionBeginUser; if (diag == 0.) { PetscCall(PetscStrcpy(diagstr,"zero")); } else { PetscCall(PetscStrcpy(diagstr,"nonzero")); } PetscCall(ISView(is,NULL)); PetscCall(MatGetLocalToGlobalMapping(A,&l2gr,&l2gc)); /* tests MatDuplicate and MatCopy */ if (diag == 0.) { PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&B)); } else { PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&B)); PetscCall(MatCopy(A,B,SAME_NONZERO_PATTERN)); } PetscCall(MatISGetLocalMat(B,&lB)); PetscCall(MatHasOperation(lB,MATOP_ZERO_ROWS,&haszerorows)); if (squaretest && haszerorows) { PetscCall(MatCreateVecs(B,&x,&b)); PetscCall(MatDuplicate(B,MAT_COPY_VALUES,&B2)); PetscCall(VecSetLocalToGlobalMapping(b,l2gr)); PetscCall(VecSetLocalToGlobalMapping(x,l2gc)); PetscCall(VecSetRandom(x,NULL)); PetscCall(VecSetRandom(b,NULL)); /* mimic b[is] = x[is] */ PetscCall(VecDuplicate(b,&b2)); PetscCall(VecSetLocalToGlobalMapping(b2,l2gr)); PetscCall(VecCopy(b,b2)); PetscCall(ISGetLocalSize(is,&n)); PetscCall(ISGetIndices(is,&idxs)); PetscCall(VecGetSize(x,&N)); for (i=0;i