static char help[] = "Tests the use of interface functions for MATIS matrices and 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,*Asub,*Bsub; Vec x,y; MatInfo info; ISLocalToGlobalMapping cmap,rmap; IS is,is2,reven,rodd,ceven,codd; IS *rows,*cols; IS irow[2], icol[2]; PetscLayout rlayout, clayout; const PetscInt *rrange, *crange; MatType lmtype; PetscScalar diag = 2.; PetscInt n,m,i,lm,ln; PetscInt rst,ren,cst,cen,nr,nc; PetscMPIInt rank,size,lrank,rrank; PetscBool testT,squaretest,isaij; PetscBool permute = PETSC_FALSE, negmap = PETSC_FALSE, repmap = PETSC_FALSE; PetscBool diffmap = PETSC_TRUE, symmetric = PETSC_FALSE, issymmetric; PetscFunctionBeginUser; 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)); /* test MatCreateSubMatrices */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatCreateSubMatrices\n")); PetscCall(MatGetLayouts(A,&rlayout,&clayout)); PetscCall(PetscLayoutGetRanges(rlayout,&rrange)); PetscCall(PetscLayoutGetRanges(clayout,&crange)); lrank = (size + rank - 1)%size; rrank = (rank + 1)%size; PetscCall(ISCreateStride(PETSC_COMM_SELF,(rrange[lrank+1] - rrange[lrank]),rrange[lrank],1,&irow[0])); PetscCall(ISCreateStride(PETSC_COMM_SELF,(crange[rrank+1] - crange[rrank]),crange[rrank],1,&icol[0])); PetscCall(ISCreateStride(PETSC_COMM_SELF,(rrange[rrank+1] - rrange[rrank]),rrange[rrank],1,&irow[1])); PetscCall(ISCreateStride(PETSC_COMM_SELF,(crange[lrank+1] - crange[lrank]),crange[lrank],1,&icol[1])); PetscCall(MatCreateSubMatrices(A,2,irow,icol,MAT_INITIAL_MATRIX,&Asub)); PetscCall(MatCreateSubMatrices(B,2,irow,icol,MAT_INITIAL_MATRIX,&Bsub)); PetscCall(CheckMat(Asub[0],Bsub[0],PETSC_FALSE,"MatCreateSubMatrices[0]")); PetscCall(CheckMat(Asub[1],Bsub[1],PETSC_FALSE,"MatCreateSubMatrices[1]")); PetscCall(MatCreateSubMatrices(A,2,irow,icol,MAT_REUSE_MATRIX,&Asub)); PetscCall(MatCreateSubMatrices(B,2,irow,icol,MAT_REUSE_MATRIX,&Bsub)); PetscCall(CheckMat(Asub[0],Bsub[0],PETSC_FALSE,"MatCreateSubMatrices[0]")); PetscCall(CheckMat(Asub[1],Bsub[1],PETSC_FALSE,"MatCreateSubMatrices[1]")); PetscCall(MatDestroySubMatrices(2,&Asub)); PetscCall(MatDestroySubMatrices(2,&Bsub)); PetscCall(ISDestroy(&irow[0])); PetscCall(ISDestroy(&irow[1])); PetscCall(ISDestroy(&icol[0])); PetscCall(ISDestroy(&icol[1])); /* 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 */ PetscInt *idx0, *idx1, n0, n1; IS Ais[2], Bis[2]; /* 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)); /* test MatIncreaseOverlap */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatIncreaseOverlap\n")); PetscCall(MatGetOwnershipRange(A,&rst,&ren)); n0 = (ren - rst)/2; n1 = (ren - rst)/3; PetscCall(PetscMalloc1(n0,&idx0)); PetscCall(PetscMalloc1(n1,&idx1)); for (i = 0; i < n0; i++) idx0[i] = ren - i - 1; for (i = 0; i < n1; i++) idx1[i] = rst + i; PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,n0,idx0,PETSC_OWN_POINTER,&Ais[0])); PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,n1,idx1,PETSC_OWN_POINTER,&Ais[1])); PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,n0,idx0,PETSC_COPY_VALUES,&Bis[0])); PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,n1,idx1,PETSC_COPY_VALUES,&Bis[1])); PetscCall(MatIncreaseOverlap(A,2,Ais,3)); PetscCall(MatIncreaseOverlap(B,2,Bis,3)); /* Non deterministic output! */ PetscCall(ISSort(Ais[0])); PetscCall(ISSort(Ais[1])); PetscCall(ISSort(Bis[0])); PetscCall(ISSort(Bis[1])); PetscCall(ISView(Ais[0],NULL)); PetscCall(ISView(Bis[0],NULL)); PetscCall(ISView(Ais[1],NULL)); PetscCall(ISView(Bis[1],NULL)); PetscCall(MatCreateSubMatrices(A,2,Ais,Ais,MAT_INITIAL_MATRIX,&Asub)); PetscCall(MatCreateSubMatrices(B,2,Bis,Ais,MAT_INITIAL_MATRIX,&Bsub)); PetscCall(CheckMat(Asub[0],Bsub[0],PETSC_FALSE,"MatIncreaseOverlap[0]")); PetscCall(CheckMat(Asub[1],Bsub[1],PETSC_FALSE,"MatIncreaseOverlap[1]")); PetscCall(MatDestroySubMatrices(2,&Asub)); PetscCall(MatDestroySubMatrices(2,&Bsub)); PetscCall(ISDestroy(&Ais[0])); PetscCall(ISDestroy(&Ais[1])); PetscCall(ISDestroy(&Bis[0])); PetscCall(ISDestroy(&Bis[1])); } 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)); } } } } /* test MatGetDiagonalBlock */ PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Test MatGetDiagonalBlock\n")); PetscCall(MatGetDiagonalBlock(A,&A2)); PetscCall(MatGetDiagonalBlock(B,&B2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatGetDiagonalBlock")); PetscCall(MatScale(A,2.0)); PetscCall(MatScale(B,2.0)); PetscCall(MatGetDiagonalBlock(A,&A2)); PetscCall(MatGetDiagonalBlock(B,&B2)); PetscCall(CheckMat(A2,B2,PETSC_FALSE,"MatGetDiagonalBlock")); /* 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,"Bcheck")); PetscCall(MatView(Bcheck,NULL)); if (B) { PetscCall(PetscObjectSetName((PetscObject)B,"B")); PetscCall(MatView(B,NULL)); PetscCall(MatDestroy(&Bcheck)); PetscCall(MatConvert(A,MATAIJ,MAT_INITIAL_MATRIX,&Bcheck)); PetscCall(PetscObjectSetName((PetscObject)Bcheck,"Assembled A")); PetscCall(MatView(Bcheck,NULL)); } PetscCall(MatDestroy(&Bcheck)); PetscCall(PetscObjectSetName((PetscObject)A,"A")); PetscCall(MatView(A,NULL)); PetscCall(MatGetLocalToGlobalMapping(A,&rl2g,&cl2g)); if (rl2g) PetscCall(ISLocalToGlobalMappingView(rl2g,NULL)); if (cl2g) PetscCall(ISLocalToGlobalMappingView(cl2g,NULL)); SETERRQ(PetscObjectComm((PetscObject)A),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