@@ -3,25 +3,29 @@ module PetscConvergenceModule
3
3
use petscksp
4
4
use KindModule, only: I4B, DP
5
5
use ConstantsModule, only: DPREC, DZERO
6
+ use SimModule, only: store_error
7
+ use SimVariablesModule, only: errmsg
6
8
use ListModule
7
9
use ConvergenceSummaryModule
8
10
use ImsLinearSettingsModule
9
11
implicit none
10
12
private
11
13
12
- public :: petsc_check_convergence
14
+ public :: petsc_cnvg_check
13
15
public :: KSPSetConvergenceTest
14
16
15
17
! TODO_MJR: this could be smaller, find a bound
16
18
real (DP), private , parameter :: RNORM_L2_TOL = DPREC
17
19
18
- ! < Context for the custom convergence check
20
+ ! Context for the custom convergence check
19
21
type, public :: PetscCnvgCtxType
20
22
Vec :: x_old ! < x vector from the previous iteration
21
23
Vec :: delta_x ! < delta in x w.r.t. previous iteration
22
24
Vec :: residual ! < the unpreconditoned residual vector (a la IMS)
23
25
integer (I4B) :: icnvg_ims ! < IMS convergence number: 1 => converged, -1 => forces next Picard iter
24
- integer (I4B) :: icnvgopt ! < convergence option from IMS settings
26
+ integer (I4B) :: icnvgopt ! < convergence option:
27
+ ! ! 0,1,2,3,4,.. for equivalent IMS settings,
28
+ ! ! 100,... for PETSc specific settings
25
29
real (DP) :: dvclose ! < dep. variable closure criterion
26
30
real (DP) :: rclose ! < residual closure criterion
27
31
integer (I4B) :: max_its ! < maximum number of inner iterations
@@ -88,9 +92,9 @@ subroutine create(this, mat, settings, summary)
88
92
89
93
end subroutine create
90
94
91
- ! > @brief Routine to check the convergence. This is called
92
- ! < from within PETSc.
93
- subroutine petsc_check_convergence (ksp , n , rnorm_L2 , flag , context , ierr )
95
+ ! > @brief Routine to check the convergence following the configuration
96
+ ! < of IMS. (called back from the PETSc solver)
97
+ subroutine petsc_cnvg_check (ksp , n , rnorm_L2 , flag , context , ierr )
94
98
KSP :: ksp ! < Iterative context
95
99
PetscInt :: n ! < Iteration number
96
100
PetscReal :: rnorm_L2 ! < 2-norm (preconditioned) residual value
@@ -99,15 +103,9 @@ subroutine petsc_check_convergence(ksp, n, rnorm_L2, flag, context, ierr)
99
103
PetscErrorCode :: ierr ! < error
100
104
! local
101
105
PetscReal, parameter :: min_one = - 1.0
102
- PetscReal, dimension (:), pointer :: local_dx, local_res
103
- PetscReal :: xnorm_inf_ims, rnorm_inf_ims, rnorm_L2_ims
104
- PetscReal :: dvmax_model, rmax_model
105
- PetscInt :: idx_dv, idx_r
106
- Vec :: x, rhs
107
- Mat :: Amat
106
+ PetscReal :: xnorm_inf, rnorm0, rnorm_inf_ims, rnorm_L2_ims
107
+ Vec :: x, res
108
108
type (ConvergenceSummaryType), pointer :: summary
109
- PetscInt :: iter_cnt
110
- PetscInt :: i, j, istart, iend
111
109
112
110
summary = > context% cnvg_summary
113
111
@@ -116,25 +114,25 @@ subroutine petsc_check_convergence(ksp, n, rnorm_L2, flag, context, ierr)
116
114
call KSPBuildSolution(ksp, PETSC_NULL_VEC, x, ierr)
117
115
CHKERRQ(ierr)
118
116
119
- call KSPGetRhs(ksp, rhs, ierr)
120
- CHKERRQ(ierr)
121
-
122
- call KSPGetOperators(ksp, Amat, PETSC_NULL_MAT, ierr)
123
- CHKERRQ(ierr)
124
-
125
- call MatMult(Amat, x, context% residual, ierr)
126
- CHKERRQ(ierr)
127
-
128
- ! y = x + beta y (i.e. r = b - A*x)
129
- call VecAYPX(context% residual, - 1.0_DP , rhs, ierr)
117
+ ! for CG the KSPBuildResidual returns the work vector directly,
118
+ ! but BCGS (and possibly others) will do the matrix multiplication
119
+ call KSPBuildResidual(ksp, PETSC_NULL_VEC, PETSC_NULL_VEC, res, ierr)
130
120
CHKERRQ(ierr)
131
121
132
- call VecNorm(context% residual, NORM_2, rnorm_L2_ims, ierr)
133
- CHKERRQ(ierr)
122
+ rnorm0 = huge (rnorm0)
123
+ if (context% icnvgopt == 2 .or. &
124
+ context% icnvgopt == 3 .or. &
125
+ context% icnvgopt == 4 ) then
126
+ call VecNorm(res, NORM_2, rnorm_L2_ims, ierr)
127
+ rnorm0 = rnorm_L2_ims
128
+ CHKERRQ(ierr)
129
+ else if (context% icnvgopt == 100 ) then
130
+ rnorm0 = rnorm_L2
131
+ end if
134
132
135
133
! n == 0 is before the iteration starts
136
134
if (n == 0 ) then
137
- context% rnorm_L2_init = rnorm_L2_ims
135
+ context% rnorm_L2_init = rnorm0
138
136
if (rnorm_L2 < RNORM_L2_TOL) then
139
137
! exact solution found
140
138
flag = KSP_CONVERGED_HAPPY_BREAKDOWN
@@ -144,80 +142,45 @@ subroutine petsc_check_convergence(ksp, n, rnorm_L2, flag, context, ierr)
144
142
flag = KSP_CONVERGED_ITERATING
145
143
end if
146
144
! early return
145
+ call VecDestroy(res, ierr)
146
+ CHKERRQ(ierr)
147
147
return
148
148
end if
149
149
150
- ! increment iteration counter
151
- summary% iter_cnt = summary% iter_cnt + 1
152
- iter_cnt = summary% iter_cnt
153
-
154
- if (summary% nitermax > 1 ) then
155
- summary% itinner(iter_cnt) = n
156
- do i = 1 , summary% convnmod
157
- summary% convdvmax(i, iter_cnt) = DZERO
158
- summary% convlocdv(i, iter_cnt) = 0
159
- summary% convrmax(i, iter_cnt) = DZERO
160
- summary% convlocr(i, iter_cnt) = 0
161
- end do
162
- end if
163
-
164
150
call VecWAXPY(context% delta_x, min_one, context% x_old, x, ierr)
165
151
CHKERRQ(ierr)
166
152
167
- call VecNorm(context% delta_x, NORM_INFINITY, xnorm_inf_ims , ierr)
153
+ call VecNorm(context% delta_x, NORM_INFINITY, xnorm_inf , ierr)
168
154
CHKERRQ(ierr)
169
155
170
- rnorm_inf_ims = 0.0
156
+ rnorm_inf_ims = huge (rnorm_inf_ims)
171
157
if (context% icnvgopt == 0 .or. context% icnvgopt == 1 ) then
172
- call VecNorm(context % residual , NORM_INFINITY, rnorm_inf_ims, ierr)
158
+ call VecNorm(res , NORM_INFINITY, rnorm_inf_ims, ierr)
173
159
CHKERRQ(ierr)
174
160
end if
175
161
176
162
call VecCopy(x, context% x_old, ierr)
177
163
CHKERRQ(ierr)
178
164
179
- ! get dv and dr per local model (readonly!)
180
- call VecGetArrayReadF90(context% delta_x, local_dx, ierr)
181
- CHKERRQ(ierr)
182
- call VecGetArrayReadF90(context% residual, local_res, ierr)
183
- CHKERRQ(ierr)
184
- do i = 1 , summary% convnmod
185
- ! reset
186
- dvmax_model = DZERO
187
- idx_dv = 0
188
- rmax_model = DZERO
189
- idx_r = 0
190
- ! get first and last model index
191
- istart = summary% model_bounds(i)
192
- iend = summary% model_bounds(i + 1 ) - 1
193
- do j = istart, iend
194
- if (abs (local_dx(j)) > abs (dvmax_model)) then
195
- dvmax_model = local_dx(j)
196
- idx_dv = j
197
- end if
198
- if (abs (local_res(j)) > abs (rmax_model)) then
199
- rmax_model = local_res(j)
200
- idx_r = j
201
- end if
202
- end do
203
- if (summary% nitermax > 1 ) then
204
- summary% convdvmax(i, iter_cnt) = dvmax_model
205
- summary% convlocdv(i, iter_cnt) = idx_dv
206
- summary% convrmax(i, iter_cnt) = rmax_model
207
- summary% convlocr(i, iter_cnt) = idx_r
208
- end if
209
- end do
210
- call VecRestoreArrayF90(context% delta_x, local_dx, ierr)
211
- CHKERRQ(ierr)
212
- call VecRestoreArrayF90(context% residual, local_res, ierr)
213
- CHKERRQ(ierr)
165
+ ! fill the summary for reporting
166
+ call fill_cnvg_summary(summary, context% delta_x, res, n)
214
167
215
168
if (rnorm_L2 < RNORM_L2_TOL) then
216
169
! exact solution, set to 'converged'
217
170
flag = KSP_CONVERGED_HAPPY_BREAKDOWN
218
- else
171
+ else if (context % icnvgopt < 100 ) then
219
172
! IMS check on convergence
220
- flag = apply_check(context, n, xnorm_inf_ims, rnorm_inf_ims, rnorm_L2_ims)
173
+ flag = apply_check(context, n, xnorm_inf, rnorm_inf_ims, rnorm_L2_ims)
174
+ else if (context% icnvgopt == 100 ) then
175
+ ! use PETSc rnorm directly
176
+ flag = KSP_CONVERGED_ITERATING
177
+ if (xnorm_inf < context% dvclose .and. rnorm_L2 < context% rclose) then
178
+ flag = KSP_CONVERGED_HAPPY_BREAKDOWN
179
+ end if
180
+ else
181
+ ! invalid option somehow
182
+ write (errmsg, ' (a,i0)' ) " Invalid convergence option: " , context% icnvgopt
183
+ call store_error(errmsg, .true. )
221
184
end if
222
185
223
186
if (flag == KSP_CONVERGED_ITERATING) then
@@ -227,7 +190,10 @@ subroutine petsc_check_convergence(ksp, n, rnorm_L2, flag, context, ierr)
227
190
end if
228
191
end if
229
192
230
- end subroutine petsc_check_convergence
193
+ call VecDestroy(res, ierr)
194
+ CHKERRQ(ierr)
195
+
196
+ end subroutine petsc_cnvg_check
231
197
232
198
! > @brief Apply the IMS convergence check
233
199
! <
@@ -268,6 +234,73 @@ function apply_check(ctx, nit, dvmax, rnorm_inf, rnorm_L2) result(flag)
268
234
269
235
end function apply_check
270
236
237
+ ! > @brief Fill the convergence summary from the context
238
+ ! <
239
+ subroutine fill_cnvg_summary (summary , dx , res , n )
240
+ type (ConvergenceSummaryType), pointer :: summary ! < the convergence summary
241
+ Vec :: dx ! < the vector with changes in x
242
+ Vec :: res ! < the residual vector
243
+ PetscInt :: n ! < the PETSc iteration number
244
+ ! local
245
+ PetscReal, dimension (:), pointer :: local_dx, local_res
246
+ PetscReal :: dvmax_model, rmax_model
247
+ PetscErrorCode :: ierr
248
+ PetscInt :: idx_dv, idx_r
249
+ PetscInt :: i, j, istart, iend
250
+ PetscInt :: iter_cnt
251
+
252
+ ! increment iteration counter
253
+ summary% iter_cnt = summary% iter_cnt + 1
254
+ iter_cnt = summary% iter_cnt
255
+
256
+ if (summary% nitermax > 1 ) then
257
+ summary% itinner(iter_cnt) = n
258
+ do i = 1 , summary% convnmod
259
+ summary% convdvmax(i, iter_cnt) = DZERO
260
+ summary% convlocdv(i, iter_cnt) = 0
261
+ summary% convrmax(i, iter_cnt) = DZERO
262
+ summary% convlocr(i, iter_cnt) = 0
263
+ end do
264
+ end if
265
+
266
+ ! get dv and dr per local model (readonly!)
267
+ call VecGetArrayReadF90(dx, local_dx, ierr)
268
+ CHKERRQ(ierr)
269
+ call VecGetArrayReadF90(res, local_res, ierr)
270
+ CHKERRQ(ierr)
271
+ do i = 1 , summary% convnmod
272
+ ! reset
273
+ dvmax_model = DZERO
274
+ idx_dv = 0
275
+ rmax_model = DZERO
276
+ idx_r = 0
277
+ ! get first and last model index
278
+ istart = summary% model_bounds(i)
279
+ iend = summary% model_bounds(i + 1 ) - 1
280
+ do j = istart, iend
281
+ if (abs (local_dx(j)) > abs (dvmax_model)) then
282
+ dvmax_model = local_dx(j)
283
+ idx_dv = j
284
+ end if
285
+ if (abs (local_res(j)) > abs (rmax_model)) then
286
+ rmax_model = local_res(j)
287
+ idx_r = j
288
+ end if
289
+ end do
290
+ if (summary% nitermax > 1 ) then
291
+ summary% convdvmax(i, iter_cnt) = dvmax_model
292
+ summary% convlocdv(i, iter_cnt) = idx_dv
293
+ summary% convrmax(i, iter_cnt) = rmax_model
294
+ summary% convlocr(i, iter_cnt) = idx_r
295
+ end if
296
+ end do
297
+ call VecRestoreArrayF90(dx, local_dx, ierr)
298
+ CHKERRQ(ierr)
299
+ call VecRestoreArrayF90(res, local_res, ierr)
300
+ CHKERRQ(ierr)
301
+
302
+ end subroutine fill_cnvg_summary
303
+
271
304
subroutine destroy (this )
272
305
class(PetscCnvgCtxType) :: this
273
306
! local
0 commit comments