https://urldefense.us/v3/__https://gitlab.com/petsc/petsc/-/merge_requests/8825__;!!G_uCfscf7eWS!bN5mKdIPW5Qb1phs3E5csHyDe8rTEZ1Wg5FYGcuTnKoIRKJqNhC4ydBAK9k4w-OY6HGXdZdeTCdxXp3afWUypHg$
> On Nov 4, 2025, at 11:14 AM, Moral Sanchez, Elena > <[email protected]> wrote: > > Dear Barry, > Thank you for the clear answer. Indeed, it would be useful to know that they > are both stored in PC, that PCSetOperators may overwrite KSPSetOperators and > that the order (1 for A, 2 for PC) is the order that appears in KSPView. > > In any case, it is clear to me now. Thanks for the help! > Cheers, > Elena > From: Barry Smith <[email protected] <mailto:[email protected]>> > Sent: 04 November 2025 16:08:21 > To: Moral Sanchez, Elena > Cc: PETSc > Subject: Re: [petsc-users] norm of KSPBuildResidual does not match norm > computed from KSPBuildSolution > > The preconditioner is always built from the second of the two matrices > passed in KSPSetOperators() or PCSetOperators(). In the first case below both > matrices are the same (the nest matrix) and so diagonal is extracted from the > nest matrix (which is the only matrix). In the second case below the first > matrix is custom and the second is the next matrix, again the preconditioner > is constructed from the second one. > > linear system matrix = precond matrix: > Mat Object: 1 MPI process > type: nest > rows=524, cols=524 > Matrix object: > type=nest, rows=3, cols=3 > MatNest structure: > (0,0) : type=mpiaij, rows=176, cols=176 > (0,1) : NULL > (0,2) : NULL > (1,0) : NULL > (1,1) : type=mpiaij, rows=172, cols=172 > (1,2) : NULL > (2,0) : NULL > (2,1) : NULL > (2,2) : type=mpiaij, rows=176, cols=176 > > Mat Object: 1 MPI process > type: python > Python: __main__.LHSOperator > Mat Object: 1 MPI process > type: nest > Matrix object: > type=nest, rows=3, cols=3 > MatNest structure: > (0,0) : type=mpiaij, rows=176, cols=176 > (0,1) : NULL > (0,2) : NULL > (1,0) : NULL > (1,1) : type=mpiaij, rows=172, cols=172 > (1,2) : NULL > (2,0) : NULL > (2,1) : NULL > (2,2) : type=mpiaij, rows=176, cols=176 > > > The arguments to KSPSetOperators() and PCSetOperators() are stored in the > same place (inside the PC) > > In fact, > > PetscErrorCode KSPSetOperators(KSP ksp, Mat Amat, Mat Pmat) > { > .... > PetscCall(PCSetOperators(ksp->pc, Amat, Pmat)); > > > > so when you call > > precond.setOperators(A=nest_mass_matrix, P=None) > ksp.setPC(precond) > > you are overwriting the A = lhs that you passed into ksp.setOperators(ksp, > lhs, None). > > Given the names ksp.setOperators() and precond.setOperators() I can see how > this can be confusing. It is reasonable to conclude that ksp.setOperators is > providing the linear system and that pc.setOperators() is providing the > matrix with which to build the preconditioner, but that is not the case. > > But the code has been this way for 31 years. I am not sure what we can change > with the documentation. Perhaps in KSPSetOperators it can say that it sets > them into the PC. > > Barry > > > > >> On Nov 4, 2025, at 4:06 AM, Moral Sanchez, Elena >> <[email protected] <mailto:[email protected]>> >> wrote: >> >> Dear Barry, >> Thanks for the fast answer. Unfortunately in my case the discrepancy is >> huge. With the flags >> -ksp_monitor_true_residual -ksp_norm_type unpreconditioned >> this is the output: >> 0 KSP unpreconditioned resid norm 5.568889644229e-01 true resid norm >> 5.568889644229e-01 ||r(i)||/||b|| 1.000000000000e+00 >> 1 KSP unpreconditioned resid norm 2.831772665189e-01 true resid norm >> 2.831772665189e-01 ||r(i)||/||b|| 5.084986139245e-01 >> 2 KSP unpreconditioned resid norm 1.875950094147e-01 true resid norm >> 1.875950094147e-01 ||r(i)||/||b|| 3.368625011435e-01 >> and this is the output of my own monitor function: >> Iter 0/10 | res = 5.57e-01/1.00e-08 | 0.0 s >> difference KSPBuildSolution and u: 0.0 >> UNPRECONDITIONED norm: 0.5568889644229376 >> PRECONDITIONED norm: 2.049041078011257 >> KSPBuildResidual 2-norm: 0.5568889644229299 >> difference KSPBuildResidual and b-A(KSPBuildSolution): 6.573603152700697e-13 >> >> Iter 1/10 | res = 2.83e-01/1.00e-08 | 0.0 s >> difference KSPBuildSolution and u: 0.0 >> UNPRECONDITIONED norm: 0.7661983589104541 >> PRECONDITIONED norm: 2.7387602134717137 >> KSPBuildResidual 2-norm: 0.2831772665189212 >> difference KSPBuildResidual and b-A(KSPBuildSolution): 0.1700718741085172 >> >> Iter 2/10 | res = 1.88e-01/1.00e-08 | 0.0 s >> difference KSPBuildSolution and u: 0.0 >> UNPRECONDITIONED norm: 0.7050518160900253 >> PRECONDITIONED norm: 2.421773833445645 >> KSPBuildResidual 2-norm: 0.18759500941469456 >> difference KSPBuildResidual and b-A(KSPBuildSolution): 0.19327058976599623 >> Here u is the vector in the KSPSolve. >> After the first iteration, the residual computed from KSPBuildSolution and >> the residual from KSPBuildResidual diverge. They are the same when I run the >> same code without preconditioner. >> Another observation is that after convergence (wrt. unpreconditioned norm == >> 2-norm of KSPBuildResidual) the solution with and without preconditioner >> looks quite different. How is this possible if my preconditioner is SPD? >> >> By the way, where can I find your implementation of "My monitor" in >> src/snes/tutorials/ex5.c? I tried to look at the Gitlab repository but could >> not find it. >> Thanks for the help. >> Cheers, >> Elena >> >> >> >> >> >> On 11/4/25 03:01, Barry Smith wrote: >>> 0 KSP unpreconditioned resid norm 1.265943996096e+00 true resid norm >>> 1.265943996096e+00 ||r(i)||/||b|| 1.000000000000e+00 >>> My monitor 0 1.265943996096e+00
