xref: /petsc/src/ksp/pc/impls/mat/tests/ex1.c (revision 345a4b08d02b12c6b890b4696d3c0881dab2c40c)
1*345a4b08SToby Isaac const char help[] = "Test PCMatSetApplyOperation() and PCMatGetApplyOperation()";
2*345a4b08SToby Isaac 
3*345a4b08SToby Isaac #include <petscpc.h>
4*345a4b08SToby Isaac 
5*345a4b08SToby Isaac static PetscErrorCode TestVecEquality(Vec x, Vec y)
6*345a4b08SToby Isaac {
7*345a4b08SToby Isaac   Vec       diff;
8*345a4b08SToby Isaac   PetscReal err, scale;
9*345a4b08SToby Isaac 
10*345a4b08SToby Isaac   PetscFunctionBegin;
11*345a4b08SToby Isaac   PetscCall(VecDuplicate(x, &diff));
12*345a4b08SToby Isaac   PetscCall(VecCopy(x, diff));
13*345a4b08SToby Isaac   PetscCall(VecAXPY(diff, -1.0, y));
14*345a4b08SToby Isaac   PetscCall(VecNorm(diff, NORM_INFINITY, &err));
15*345a4b08SToby Isaac   PetscCall(VecNorm(x, NORM_INFINITY, &scale));
16*345a4b08SToby Isaac   PetscCheck(err <= PETSC_SMALL * scale, PetscObjectComm((PetscObject)x), PETSC_ERR_PLIB, "PC operation does not match Mat operation");
17*345a4b08SToby Isaac   PetscCall(VecDestroy(&diff));
18*345a4b08SToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
19*345a4b08SToby Isaac }
20*345a4b08SToby Isaac 
21*345a4b08SToby Isaac static PetscErrorCode TestMatEquality(Mat x, Mat y)
22*345a4b08SToby Isaac {
23*345a4b08SToby Isaac   Mat       diff;
24*345a4b08SToby Isaac   PetscReal err, scale;
25*345a4b08SToby Isaac   PetscInt  m, n;
26*345a4b08SToby Isaac 
27*345a4b08SToby Isaac   PetscFunctionBegin;
28*345a4b08SToby Isaac   PetscCall(MatGetSize(x, &m, &n));
29*345a4b08SToby Isaac   PetscCall(MatDuplicate(x, MAT_COPY_VALUES, &diff));
30*345a4b08SToby Isaac   PetscCall(MatAXPY(diff, -1.0, y, SAME_NONZERO_PATTERN));
31*345a4b08SToby Isaac   PetscCall(MatNorm(diff, NORM_FROBENIUS, &err));
32*345a4b08SToby Isaac   PetscCall(MatNorm(x, NORM_FROBENIUS, &scale));
33*345a4b08SToby Isaac   PetscCheck(err < PETSC_SMALL * m * n * scale, PetscObjectComm((PetscObject)x), PETSC_ERR_PLIB, "PC operation does not match Mat operation");
34*345a4b08SToby Isaac   PetscCall(MatDestroy(&diff));
35*345a4b08SToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
36*345a4b08SToby Isaac }
37*345a4b08SToby Isaac 
38*345a4b08SToby Isaac // Test PCMat with a given operation versus a Matrix that encode the same operation relative to the original matrix
39*345a4b08SToby Isaac static PetscErrorCode TestPCMatVersusMat(PC pc, Mat A, PetscRandom rand, MatOperation op)
40*345a4b08SToby Isaac {
41*345a4b08SToby Isaac   Vec          b, x, x2;
42*345a4b08SToby Isaac   Mat          B, X, X2;
43*345a4b08SToby Isaac   MatOperation op2;
44*345a4b08SToby Isaac 
45*345a4b08SToby Isaac   PetscFunctionBegin;
46*345a4b08SToby Isaac   PetscCall(PCMatSetApplyOperation(pc, op));
47*345a4b08SToby Isaac   PetscCall(PCView(pc, PETSC_VIEWER_STDOUT_SELF));
48*345a4b08SToby Isaac   PetscCall(PCMatGetApplyOperation(pc, &op2));
49*345a4b08SToby Isaac   PetscCheck(op == op2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Input and output MatOperation differ");
50*345a4b08SToby Isaac 
51*345a4b08SToby Isaac   PetscCall(MatCreateVecs(A, &b, &x));
52*345a4b08SToby Isaac   PetscCall(VecDuplicate(x, &x2));
53*345a4b08SToby Isaac   PetscCall(VecSetRandom(b, rand));
54*345a4b08SToby Isaac 
55*345a4b08SToby Isaac   PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
56*345a4b08SToby Isaac   PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &X2));
57*345a4b08SToby Isaac   PetscCall(MatSetRandom(B, rand));
58*345a4b08SToby Isaac 
59*345a4b08SToby Isaac   PetscCall(MatMult(A, b, x));
60*345a4b08SToby Isaac   PetscCall(PCApply(pc, b, x2));
61*345a4b08SToby Isaac   PetscCall(TestVecEquality(x, x2));
62*345a4b08SToby Isaac 
63*345a4b08SToby Isaac   PetscCall(MatMultTranspose(A, b, x));
64*345a4b08SToby Isaac   PetscCall(PCApplyTranspose(pc, b, x2));
65*345a4b08SToby Isaac   PetscCall(TestVecEquality(x, x2));
66*345a4b08SToby Isaac 
67*345a4b08SToby Isaac   PetscCall(MatMatMult(A, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &X));
68*345a4b08SToby Isaac   PetscCall(PCMatApply(pc, B, X2));
69*345a4b08SToby Isaac   PetscCall(TestMatEquality(X, X2));
70*345a4b08SToby Isaac 
71*345a4b08SToby Isaac   PetscCall(MatDestroy(&X2));
72*345a4b08SToby Isaac   PetscCall(MatDestroy(&X));
73*345a4b08SToby Isaac   PetscCall(MatDestroy(&B));
74*345a4b08SToby Isaac   PetscCall(VecDestroy(&x2));
75*345a4b08SToby Isaac   PetscCall(VecDestroy(&x));
76*345a4b08SToby Isaac   PetscCall(VecDestroy(&b));
77*345a4b08SToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
78*345a4b08SToby Isaac }
79*345a4b08SToby Isaac 
80*345a4b08SToby Isaac int main(int argc, char **argv)
81*345a4b08SToby Isaac {
82*345a4b08SToby Isaac   PetscInt    n = 10;
83*345a4b08SToby Isaac   Mat         A, AT, AH, II, Ainv, AinvT;
84*345a4b08SToby Isaac   MPI_Comm    comm;
85*345a4b08SToby Isaac   PC          pc;
86*345a4b08SToby Isaac   PetscRandom rand;
87*345a4b08SToby Isaac 
88*345a4b08SToby Isaac   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
89*345a4b08SToby Isaac   comm = PETSC_COMM_SELF;
90*345a4b08SToby Isaac 
91*345a4b08SToby Isaac   PetscCall(PetscRandomCreate(comm, &rand));
92*345a4b08SToby Isaac   if (PetscDefined(USE_COMPLEX)) {
93*345a4b08SToby Isaac     PetscScalar i = PetscSqrtScalar(-1.0);
94*345a4b08SToby Isaac     PetscCall(PetscRandomSetInterval(rand, -1.0 - i, 1.0 + i));
95*345a4b08SToby Isaac   } else {
96*345a4b08SToby Isaac     PetscCall(PetscRandomSetInterval(rand, -1.0, 1.0));
97*345a4b08SToby Isaac   }
98*345a4b08SToby Isaac 
99*345a4b08SToby Isaac   PetscCall(MatCreateSeqDense(comm, n, n, NULL, &A));
100*345a4b08SToby Isaac   PetscCall(MatSetRandom(A, rand));
101*345a4b08SToby Isaac 
102*345a4b08SToby Isaac   PetscCall(PCCreate(comm, &pc));
103*345a4b08SToby Isaac   PetscCall(PCSetType(pc, PCMAT));
104*345a4b08SToby Isaac   PetscCall(PCSetOperators(pc, A, A));
105*345a4b08SToby Isaac   PetscCall(PCSetUp(pc));
106*345a4b08SToby Isaac 
107*345a4b08SToby Isaac   MatOperation default_op;
108*345a4b08SToby Isaac   PetscCall(PCMatGetApplyOperation(pc, &default_op));
109*345a4b08SToby Isaac   PetscCheck(default_op == MATOP_MULT, comm, PETSC_ERR_PLIB, "Default operation has changed");
110*345a4b08SToby Isaac 
111*345a4b08SToby Isaac   // Test setting an invalid operation
112*345a4b08SToby Isaac   PetscCall(PetscPushErrorHandler(PetscReturnErrorHandler, NULL));
113*345a4b08SToby Isaac   PetscErrorCode ierr = PCMatSetApplyOperation(pc, MATOP_SET_VALUES);
114*345a4b08SToby Isaac   PetscCall(PetscPopErrorHandler());
115*345a4b08SToby Isaac   PetscCheck(ierr == PETSC_ERR_ARG_INCOMP, comm, PETSC_ERR_PLIB, "Wrong error message for unsupported MatOperation");
116*345a4b08SToby Isaac 
117*345a4b08SToby Isaac   PetscCall(TestPCMatVersusMat(pc, A, rand, MATOP_MULT));
118*345a4b08SToby Isaac 
119*345a4b08SToby Isaac   PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &AT));
120*345a4b08SToby Isaac   PetscCall(TestPCMatVersusMat(pc, AT, rand, MATOP_MULT_TRANSPOSE));
121*345a4b08SToby Isaac 
122*345a4b08SToby Isaac   PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &AH));
123*345a4b08SToby Isaac   PetscCall(TestPCMatVersusMat(pc, AH, rand, MATOP_MULT_HERMITIAN_TRANSPOSE));
124*345a4b08SToby Isaac 
125*345a4b08SToby Isaac   PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &II));
126*345a4b08SToby Isaac   PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &Ainv));
127*345a4b08SToby Isaac   PetscCall(MatZeroEntries(II));
128*345a4b08SToby Isaac   PetscCall(MatShift(II, 1.0));
129*345a4b08SToby Isaac   PetscCall(MatLUFactor(A, NULL, NULL, NULL));
130*345a4b08SToby Isaac   PetscCall(MatMatSolve(A, II, Ainv));
131*345a4b08SToby Isaac   PetscCall(PCSetOperators(pc, A, A));
132*345a4b08SToby Isaac   PetscCall(TestPCMatVersusMat(pc, Ainv, rand, MATOP_SOLVE));
133*345a4b08SToby Isaac 
134*345a4b08SToby Isaac   PetscCall(MatTranspose(Ainv, MAT_INITIAL_MATRIX, &AinvT));
135*345a4b08SToby Isaac   PetscCall(TestPCMatVersusMat(pc, AinvT, rand, MATOP_SOLVE_TRANSPOSE));
136*345a4b08SToby Isaac 
137*345a4b08SToby Isaac   PetscCall(PCDestroy(&pc));
138*345a4b08SToby Isaac   PetscCall(MatDestroy(&AinvT));
139*345a4b08SToby Isaac   PetscCall(MatDestroy(&Ainv));
140*345a4b08SToby Isaac   PetscCall(MatDestroy(&II));
141*345a4b08SToby Isaac   PetscCall(MatDestroy(&AH));
142*345a4b08SToby Isaac   PetscCall(MatDestroy(&AT));
143*345a4b08SToby Isaac   PetscCall(MatDestroy(&A));
144*345a4b08SToby Isaac   PetscCall(PetscRandomDestroy(&rand));
145*345a4b08SToby Isaac   PetscCall(PetscFinalize());
146*345a4b08SToby Isaac   return 0;
147*345a4b08SToby Isaac }
148*345a4b08SToby Isaac 
149*345a4b08SToby Isaac /*TEST
150*345a4b08SToby Isaac 
151*345a4b08SToby Isaac   test:
152*345a4b08SToby Isaac     suffix: 0
153*345a4b08SToby Isaac 
154*345a4b08SToby Isaac TEST*/
155