1345a4b08SToby Isaac const char help[] = "Test PCMatSetApplyOperation() and PCMatGetApplyOperation()"; 2345a4b08SToby Isaac 3345a4b08SToby Isaac #include <petscpc.h> 4345a4b08SToby Isaac 5345a4b08SToby Isaac static PetscErrorCode TestVecEquality(Vec x, Vec y) 6345a4b08SToby Isaac { 7345a4b08SToby Isaac Vec diff; 8345a4b08SToby Isaac PetscReal err, scale; 9345a4b08SToby Isaac 10345a4b08SToby Isaac PetscFunctionBegin; 11345a4b08SToby Isaac PetscCall(VecDuplicate(x, &diff)); 12345a4b08SToby Isaac PetscCall(VecCopy(x, diff)); 13345a4b08SToby Isaac PetscCall(VecAXPY(diff, -1.0, y)); 14345a4b08SToby Isaac PetscCall(VecNorm(diff, NORM_INFINITY, &err)); 15345a4b08SToby Isaac PetscCall(VecNorm(x, NORM_INFINITY, &scale)); 16345a4b08SToby Isaac PetscCheck(err <= PETSC_SMALL * scale, PetscObjectComm((PetscObject)x), PETSC_ERR_PLIB, "PC operation does not match Mat operation"); 17345a4b08SToby Isaac PetscCall(VecDestroy(&diff)); 18345a4b08SToby Isaac PetscFunctionReturn(PETSC_SUCCESS); 19345a4b08SToby Isaac } 20345a4b08SToby Isaac 21345a4b08SToby Isaac static PetscErrorCode TestMatEquality(Mat x, Mat y) 22345a4b08SToby Isaac { 23345a4b08SToby Isaac Mat diff; 24345a4b08SToby Isaac PetscReal err, scale; 25345a4b08SToby Isaac PetscInt m, n; 26345a4b08SToby Isaac 27345a4b08SToby Isaac PetscFunctionBegin; 28345a4b08SToby Isaac PetscCall(MatGetSize(x, &m, &n)); 29345a4b08SToby Isaac PetscCall(MatDuplicate(x, MAT_COPY_VALUES, &diff)); 30345a4b08SToby Isaac PetscCall(MatAXPY(diff, -1.0, y, SAME_NONZERO_PATTERN)); 31345a4b08SToby Isaac PetscCall(MatNorm(diff, NORM_FROBENIUS, &err)); 32345a4b08SToby Isaac PetscCall(MatNorm(x, NORM_FROBENIUS, &scale)); 33345a4b08SToby Isaac PetscCheck(err < PETSC_SMALL * m * n * scale, PetscObjectComm((PetscObject)x), PETSC_ERR_PLIB, "PC operation does not match Mat operation"); 34345a4b08SToby Isaac PetscCall(MatDestroy(&diff)); 35345a4b08SToby Isaac PetscFunctionReturn(PETSC_SUCCESS); 36345a4b08SToby Isaac } 37345a4b08SToby Isaac 38345a4b08SToby Isaac // Test PCMat with a given operation versus a Matrix that encode the same operation relative to the original matrix 39345a4b08SToby Isaac static PetscErrorCode TestPCMatVersusMat(PC pc, Mat A, PetscRandom rand, MatOperation op) 40345a4b08SToby Isaac { 41345a4b08SToby Isaac Vec b, x, x2; 42345a4b08SToby Isaac Mat B, X, X2; 43345a4b08SToby Isaac MatOperation op2; 44345a4b08SToby Isaac 45345a4b08SToby Isaac PetscFunctionBegin; 46345a4b08SToby Isaac PetscCall(PCMatSetApplyOperation(pc, op)); 47345a4b08SToby Isaac PetscCall(PCView(pc, PETSC_VIEWER_STDOUT_SELF)); 48345a4b08SToby Isaac PetscCall(PCMatGetApplyOperation(pc, &op2)); 49345a4b08SToby Isaac PetscCheck(op == op2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Input and output MatOperation differ"); 50345a4b08SToby Isaac 51345a4b08SToby Isaac PetscCall(MatCreateVecs(A, &b, &x)); 52345a4b08SToby Isaac PetscCall(VecDuplicate(x, &x2)); 53345a4b08SToby Isaac PetscCall(VecSetRandom(b, rand)); 54345a4b08SToby Isaac 55345a4b08SToby Isaac PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B)); 56345a4b08SToby Isaac PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &X2)); 57345a4b08SToby Isaac PetscCall(MatSetRandom(B, rand)); 58345a4b08SToby Isaac 59345a4b08SToby Isaac PetscCall(MatMult(A, b, x)); 60345a4b08SToby Isaac PetscCall(PCApply(pc, b, x2)); 61345a4b08SToby Isaac PetscCall(TestVecEquality(x, x2)); 62345a4b08SToby Isaac 63345a4b08SToby Isaac PetscCall(MatMultTranspose(A, b, x)); 64345a4b08SToby Isaac PetscCall(PCApplyTranspose(pc, b, x2)); 65345a4b08SToby Isaac PetscCall(TestVecEquality(x, x2)); 66345a4b08SToby Isaac 67*fb842aefSJose E. Roman PetscCall(MatMatMult(A, B, MAT_INITIAL_MATRIX, PETSC_CURRENT, &X)); 68345a4b08SToby Isaac PetscCall(PCMatApply(pc, B, X2)); 69345a4b08SToby Isaac PetscCall(TestMatEquality(X, X2)); 70345a4b08SToby Isaac 71345a4b08SToby Isaac PetscCall(MatDestroy(&X2)); 72345a4b08SToby Isaac PetscCall(MatDestroy(&X)); 73345a4b08SToby Isaac PetscCall(MatDestroy(&B)); 74345a4b08SToby Isaac PetscCall(VecDestroy(&x2)); 75345a4b08SToby Isaac PetscCall(VecDestroy(&x)); 76345a4b08SToby Isaac PetscCall(VecDestroy(&b)); 77345a4b08SToby Isaac PetscFunctionReturn(PETSC_SUCCESS); 78345a4b08SToby Isaac } 79345a4b08SToby Isaac 80345a4b08SToby Isaac int main(int argc, char **argv) 81345a4b08SToby Isaac { 82345a4b08SToby Isaac PetscInt n = 10; 83345a4b08SToby Isaac Mat A, AT, AH, II, Ainv, AinvT; 84345a4b08SToby Isaac MPI_Comm comm; 85345a4b08SToby Isaac PC pc; 86345a4b08SToby Isaac PetscRandom rand; 87345a4b08SToby Isaac 88345a4b08SToby Isaac PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 89345a4b08SToby Isaac comm = PETSC_COMM_SELF; 90345a4b08SToby Isaac 91345a4b08SToby Isaac PetscCall(PetscRandomCreate(comm, &rand)); 92345a4b08SToby Isaac if (PetscDefined(USE_COMPLEX)) { 93345a4b08SToby Isaac PetscScalar i = PetscSqrtScalar(-1.0); 94345a4b08SToby Isaac PetscCall(PetscRandomSetInterval(rand, -1.0 - i, 1.0 + i)); 95345a4b08SToby Isaac } else { 96345a4b08SToby Isaac PetscCall(PetscRandomSetInterval(rand, -1.0, 1.0)); 97345a4b08SToby Isaac } 98345a4b08SToby Isaac 99345a4b08SToby Isaac PetscCall(MatCreateSeqDense(comm, n, n, NULL, &A)); 100345a4b08SToby Isaac PetscCall(MatSetRandom(A, rand)); 101345a4b08SToby Isaac 102345a4b08SToby Isaac PetscCall(PCCreate(comm, &pc)); 103345a4b08SToby Isaac PetscCall(PCSetType(pc, PCMAT)); 104345a4b08SToby Isaac PetscCall(PCSetOperators(pc, A, A)); 105345a4b08SToby Isaac PetscCall(PCSetUp(pc)); 106345a4b08SToby Isaac 107345a4b08SToby Isaac MatOperation default_op; 108345a4b08SToby Isaac PetscCall(PCMatGetApplyOperation(pc, &default_op)); 109345a4b08SToby Isaac PetscCheck(default_op == MATOP_MULT, comm, PETSC_ERR_PLIB, "Default operation has changed"); 110345a4b08SToby Isaac 111345a4b08SToby Isaac // Test setting an invalid operation 112345a4b08SToby Isaac PetscCall(PetscPushErrorHandler(PetscReturnErrorHandler, NULL)); 113345a4b08SToby Isaac PetscErrorCode ierr = PCMatSetApplyOperation(pc, MATOP_SET_VALUES); 114345a4b08SToby Isaac PetscCall(PetscPopErrorHandler()); 115345a4b08SToby Isaac PetscCheck(ierr == PETSC_ERR_ARG_INCOMP, comm, PETSC_ERR_PLIB, "Wrong error message for unsupported MatOperation"); 116345a4b08SToby Isaac 117345a4b08SToby Isaac PetscCall(TestPCMatVersusMat(pc, A, rand, MATOP_MULT)); 118345a4b08SToby Isaac 119345a4b08SToby Isaac PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &AT)); 120345a4b08SToby Isaac PetscCall(TestPCMatVersusMat(pc, AT, rand, MATOP_MULT_TRANSPOSE)); 121345a4b08SToby Isaac 122345a4b08SToby Isaac PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &AH)); 123345a4b08SToby Isaac PetscCall(TestPCMatVersusMat(pc, AH, rand, MATOP_MULT_HERMITIAN_TRANSPOSE)); 124345a4b08SToby Isaac 125345a4b08SToby Isaac PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &II)); 126345a4b08SToby Isaac PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &Ainv)); 127345a4b08SToby Isaac PetscCall(MatZeroEntries(II)); 128345a4b08SToby Isaac PetscCall(MatShift(II, 1.0)); 129345a4b08SToby Isaac PetscCall(MatLUFactor(A, NULL, NULL, NULL)); 130345a4b08SToby Isaac PetscCall(MatMatSolve(A, II, Ainv)); 131345a4b08SToby Isaac PetscCall(PCSetOperators(pc, A, A)); 132345a4b08SToby Isaac PetscCall(TestPCMatVersusMat(pc, Ainv, rand, MATOP_SOLVE)); 133345a4b08SToby Isaac 134345a4b08SToby Isaac PetscCall(MatTranspose(Ainv, MAT_INITIAL_MATRIX, &AinvT)); 135345a4b08SToby Isaac PetscCall(TestPCMatVersusMat(pc, AinvT, rand, MATOP_SOLVE_TRANSPOSE)); 136345a4b08SToby Isaac 137345a4b08SToby Isaac PetscCall(PCDestroy(&pc)); 138345a4b08SToby Isaac PetscCall(MatDestroy(&AinvT)); 139345a4b08SToby Isaac PetscCall(MatDestroy(&Ainv)); 140345a4b08SToby Isaac PetscCall(MatDestroy(&II)); 141345a4b08SToby Isaac PetscCall(MatDestroy(&AH)); 142345a4b08SToby Isaac PetscCall(MatDestroy(&AT)); 143345a4b08SToby Isaac PetscCall(MatDestroy(&A)); 144345a4b08SToby Isaac PetscCall(PetscRandomDestroy(&rand)); 145345a4b08SToby Isaac PetscCall(PetscFinalize()); 146345a4b08SToby Isaac return 0; 147345a4b08SToby Isaac } 148345a4b08SToby Isaac 149345a4b08SToby Isaac /*TEST 150345a4b08SToby Isaac 151345a4b08SToby Isaac test: 152345a4b08SToby Isaac suffix: 0 153345a4b08SToby Isaac 154345a4b08SToby Isaac TEST*/ 155