[petsc-users] norm of KSPBuildResidual does not match norm computed from KSPBuildSolution
Moral Sanchez, Elena
Elena.Moral.Sanchez at ipp.mpg.de
Tue Nov 4 10:14:00 CST 2025
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 <bsmith at petsc.dev>
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 <Elena.Moral.Sanchez at ipp.mpg.de> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mcs.anl.gov/pipermail/petsc-users/attachments/20251104/65147be8/attachment-0001.html>
More information about the petsc-users
mailing list