Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fhutiter/src/huti_qmr.F90
3206 views
1
module huti_qmr
2
use huti_aux
3
implicit none
4
!
5
! *
6
! * Elmer, A Finite Element Software for Multiphysical Problems
7
! *
8
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
9
! *
10
! * This library is free software; you can redistribute it and/or
11
! * modify it under the terms of the GNU Lesser General Public
12
! * License as published by the Free Software Foundation; either
13
! * version 2.1 of the License, or (at your option) any later version.
14
! *
15
! * This library is distributed in the hope that it will be useful,
16
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
! * Lesser General Public License for more details.
19
! *
20
! * You should have received a copy of the GNU Lesser General Public
21
! * License along with this library (in file ../LGPL-2.1); if not, write
22
! * to the Free Software Foundation, Inc., 51 Franklin Street,
23
! * Fifth Floor, Boston, MA 02110-1301 USA
24
! *
25
! *****************************************************************************/
26
27
!
28
! Subroutine to implement QMR iterative method (double complex)
29
!
30
31
#include "huti_fdefs.h"
32
33
!*************************************************************************
34
!
35
! This subroutine is based on a paper by Freund and Nachtigal:
36
! "An Implementation of the QMR Method Based on Coupled Two-Term
37
! Recurrences", 1994 (SIAM J. Sci. Comput, March 1994)
38
! and a book by Barret et al.:
39
! "Templates for the Solution of Linear Systems: Building Blocks for
40
! Iterative Methods", 1993.
41
!
42
! All matrix-vector operations are done externally, so we do not need
43
! to know about the matrix structure (sparse or dense). Memory allocation
44
! for the working arrays has also been done externally.
45
!
46
!*************************************************************************
47
! Work array is used in the following order:
48
! work(:,1) = v
49
! work(:,2) = v tilde
50
! work(:,3) = y
51
! work(:,4) = y tilde
52
! work(:,5) = w
53
! work(:,6) = w tilde
54
! work(:,7) = z
55
! work(:,8) = z tilde
56
! work(:,9) = p
57
! work(:,10) = p tilde
58
! work(:,11) = q
59
! work(:,12) = d
60
! work(:,13) = s
61
! work(:,14) = r
62
!
63
!*************************************************************************
64
! Definitions to make the code more understandable and to make it look
65
! like the pseudo code
66
!
67
#define X xvec
68
#define B rhsvec
69
70
#define V work(:,1)
71
#define V_ind 1
72
#define VTLD work(:,2)
73
#define VTLD_ind 2
74
#define Y work(:,3)
75
#define Y_ind 3
76
#define YTLD work(:,4)
77
#define YTLD_ind 4
78
#define W work(:,5)
79
#define W_ind 5
80
#define WTLD work(:,6)
81
#define WTLD_ind 6
82
#define Z work(:,7)
83
#define Z_ind 7
84
#define ZTLD work(:,8)
85
#define ZTLD_ind 8
86
#define P work(:,9)
87
#define P_ind 9
88
#define PTLD work(:,10)
89
#define PTLD_ind 10
90
#define Q work(:,11)
91
#define Q_ind 11
92
#define D work(:,12)
93
#define D_ind 12
94
#define S work(:,13)
95
#define S_ind 13
96
#define R work(:,14)
97
#define R_ind 14
98
!*************************************************************************
99
100
contains
101
102
!*************************************************************************
103
!*************************************************************************
104
! Single precision version
105
!*************************************************************************
106
!*************************************************************************
107
108
subroutine huti_sqmrsolv ( ndim, wrkdim, xvec, rhsvec, &
109
ipar, dpar, work, matvecsubr, pcondlsubr, &
110
pcondrsubr, dotprodfun, normfun, stopcfun )
111
use huti_interfaces
112
implicit none
113
114
procedure( mv_iface_s ), pointer :: matvecsubr
115
procedure( pc_iface_s ), pointer :: pcondlsubr
116
procedure( pc_iface_s ), pointer :: pcondrsubr
117
procedure( dotp_iface_s ), pointer :: dotprodfun
118
procedure( norm_iface_s ), pointer :: normfun
119
procedure( stopc_iface_s ), pointer :: stopcfun
120
121
! Parameters
122
123
integer :: ndim, wrkdim
124
real, dimension(ndim) :: xvec, rhsvec
125
integer, dimension(HUTI_IPAR_DFLTSIZE) :: ipar
126
double precision, dimension(HUTI_DPAR_DFLTSIZE) :: dpar
127
real, dimension(ndim,wrkdim) :: work
128
129
! Local variables
130
131
real :: beta, gamma, oldgamma, delta, rho, rhonext
132
real :: psi, theta, oldtheta, eta, epsilon
133
integer iter_count
134
real :: residual, rhsnorm, precrhsnorm
135
136
!
137
! End of variable declarations
138
!*********************************************************************
139
140
!*********************************************************************
141
! The actual QMR begins here (look the pseudo code in the
142
! "Templates.."-book on page 24)
143
!
144
! First the initialization part
145
!
146
147
iter_count = 1
148
149
! Norms of right-hand side vector are used in convergence tests
150
151
if ( HUTI_STOPC .eq. HUTI_TRESID_SCALED_BYB .or. &
152
HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYB ) then
153
rhsnorm = normfun( HUTI_NDIM, B, 1 )
154
end if
155
if ( HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYPRECB ) then
156
call pcondlsubr( P, B, ipar )
157
precrhsnorm = normfun( HUTI_NDIM, P, 1 )
158
end if
159
160
! Generate vector X if needed
161
162
if ( HUTI_INITIALX .eq. HUTI_RANDOMX ) then
163
call huti_srandvec ( X, ipar )
164
else if ( HUTI_INITIALX .ne. HUTI_USERSUPPLIEDX ) then
165
X = 1
166
end if
167
168
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
169
call matvecsubr( X, R, ipar )
170
R = B - R
171
VTLD = R
172
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
173
call pcondlsubr( Y, VTLD, ipar )
174
175
WTLD = R
176
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
177
call pcondrsubr( Z, WTLD, ipar )
178
179
rho = normfun( HUTI_NDIM, Y, 1 )
180
psi = normfun( HUTI_NDIM, Z, 1 )
181
oldgamma = 1
182
eta = -1
183
184
!
185
! This is where the loop starts (that is we continue from here after
186
! the first iteration)
187
!
188
189
300 continue
190
191
if (( rho .eq. 0 ) .or. ( psi .eq. 0 )) then
192
HUTI_INFO = HUTI_QMR_RHO_PSI
193
go to 1000
194
end if
195
196
V = VTLD / rho
197
Y = Y / rho
198
W = WTLD / psi
199
Z = Z / psi
200
delta = dotprodfun( HUTI_NDIM, Z, 1, Y, 1 )
201
202
if ( delta .eq. 0 ) then
203
HUTI_INFO = HUTI_QMR_DELTA
204
go to 1000
205
end if
206
207
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
208
call pcondrsubr( YTLD, Y, ipar )
209
210
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
211
call pcondlsubr( ZTLD, Z, ipar )
212
213
if ( iter_count .eq. 1 ) then
214
P = YTLD
215
Q = ZTLD
216
else
217
P = YTLD - ((psi * delta)/epsilon) * P
218
Q = ZTLD - ((rho * delta)/epsilon) * Q
219
end if
220
221
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
222
call matvecsubr( P, PTLD, ipar )
223
epsilon = dotprodfun( HUTI_NDIM, Q, 1, PTLD, 1 )
224
if ( epsilon .eq. 0 ) then
225
HUTI_INFO = HUTI_QMR_EPSILON
226
go to 1000
227
end if
228
229
beta = epsilon / delta
230
if ( beta .eq. 0 ) then
231
HUTI_INFO = HUTI_QMR_BETA
232
go to 1000
233
end if
234
235
VTLD = PTLD - beta * V
236
237
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
238
call pcondlsubr( Y, VTLD, ipar )
239
240
rhonext = normfun( ndim, Y, 1 )
241
242
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
243
call matvecsubr( Q, WTLD, ipar )
244
245
WTLD = WTLD - beta * W
246
247
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
248
call pcondrsubr( Z, WTLD, ipar )
249
250
psi = normfun( HUTI_NDIM, Z, 1 )
251
theta = rhonext / (oldgamma * abs( beta ))
252
gamma = 1 / sqrt( 1 + theta * theta )
253
if ( gamma .eq. 0 ) then
254
HUTI_INFO = HUTI_QMR_GAMMA
255
go to 1000
256
end if
257
258
eta = -1 * ( eta * rho * gamma * gamma ) / ( beta * oldgamma * oldgamma )
259
260
if ( iter_count .eq. 1 ) then
261
D = eta * P
262
S = eta * PTLD
263
else
264
D = eta * P + ( oldtheta * gamma ) * ( oldtheta * gamma ) * D
265
S = eta * PTLD + ( oldtheta * gamma ) * ( oldtheta * gamma ) * S
266
end if
267
X = X + D
268
R = R - S
269
270
!
271
! Check the convergence against selected stopping criterion
272
!
273
274
select case (HUTI_STOPC)
275
case (HUTI_TRUERESIDUAL)
276
call matvecsubr( X, YTLD, ipar )
277
YTLD = YTLD - B
278
residual = normfun( HUTI_NDIM, YTLD, 1 )
279
case (HUTI_TRESID_SCALED_BYB)
280
call matvecsubr( X, YTLD, ipar )
281
YTLD = YTLD - B
282
residual = normfun( HUTI_NDIM, YTLD, 1 ) / rhsnorm
283
case (HUTI_PSEUDORESIDUAL)
284
residual = normfun( HUTI_NDIM, R, 1 )
285
case (HUTI_PRESID_SCALED_BYB)
286
residual = normfun( HUTI_NDIM, R, 1 ) / rhsnorm
287
case (HUTI_PRESID_SCALED_BYPRECB)
288
residual = normfun( HUTI_NDIM, R, 1 ) / precrhsnorm
289
case (HUTI_XDIFF_NORM)
290
residual = normfun( HUTI_NDIM, D, 1 )
291
case (HUTI_USUPPLIED_STOPC)
292
residual = stopcfun( X, B, R, ipar, dpar )
293
case default
294
call matvecsubr( X, YTLD, ipar )
295
YTLD = YTLD - B
296
residual = normfun( HUTI_NDIM, YTLD, 1 )
297
end select
298
299
!
300
! Print debugging output if desired
301
!
302
303
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
304
if ( mod(iter_count, HUTI_DBUGLVL) .eq. 0 ) then
305
write (*, '(I8, E11.4)') iter_count, residual
306
end if
307
end if
308
309
if ( residual .lt. HUTI_TOLERANCE ) then
310
HUTI_INFO = HUTI_CONVERGENCE
311
go to 1000
312
end if
313
314
IF( residual /= residual .OR. residual > HUTI_MAXTOLERANCE ) THEN
315
HUTI_INFO = HUTI_DIVERGENCE
316
GOTO 1000
317
END IF
318
319
rho = rhonext
320
oldgamma = gamma
321
oldtheta = theta
322
323
!
324
! Return back to the iteration loop (without initialization)
325
!
326
327
iter_count = iter_count + 1
328
if ( iter_count .gt. HUTI_MAXIT ) then
329
HUTI_INFO = HUTI_MAXITER
330
go to 1000
331
end if
332
333
go to 300
334
335
!
336
! This is where we exit last time (after enough iterations or breakdown)
337
!
338
339
1000 continue
340
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
341
write (*, '(I8, E11.4)') iter_count, residual
342
end if
343
344
HUTI_ITERS = iter_count
345
return
346
347
! End of execution
348
!*********************************************************************
349
350
end subroutine huti_sqmrsolv
351
352
!*********************************************************************
353
354
355
356
357
!*************************************************************************
358
!*************************************************************************
359
! Double precision version
360
!*************************************************************************
361
!*************************************************************************
362
363
subroutine huti_dqmrsolv ( ndim, wrkdim, xvec, rhsvec, &
364
ipar, dpar, work, matvecsubr, pcondlsubr, &
365
pcondrsubr, dotprodfun, normfun, stopcfun )
366
use huti_interfaces
367
implicit none
368
369
procedure( mv_iface_d ), pointer :: matvecsubr
370
procedure( pc_iface_d ), pointer :: pcondlsubr
371
procedure( pc_iface_d ), pointer :: pcondrsubr
372
procedure( dotp_iface_d ), pointer :: dotprodfun
373
procedure( norm_iface_d ), pointer :: normfun
374
procedure( stopc_iface_d ), pointer :: stopcfun
375
376
! Parameters
377
378
integer :: ndim, wrkdim
379
double precision, dimension(ndim) :: xvec, rhsvec
380
integer, dimension(HUTI_IPAR_DFLTSIZE) :: ipar
381
double precision, dimension(HUTI_DPAR_DFLTSIZE) :: dpar
382
double precision, dimension(ndim,wrkdim) :: work
383
384
! Local variables
385
386
double precision :: beta, gamma, oldgamma, delta, rho, rhonext
387
double precision :: psi, theta, oldtheta, eta, epsilon
388
integer iter_count
389
double precision :: residual, rhsnorm, precrhsnorm
390
391
!
392
! End of variable declarations
393
!*********************************************************************
394
395
!*********************************************************************
396
! The actual QMR begins here (look the pseudo code in the
397
! "Templates.."-book on page 24)
398
!
399
! First the initialization part
400
!
401
402
iter_count = 1
403
404
! Norms of right-hand side vector are used in convergence tests
405
406
if ( HUTI_STOPC .eq. HUTI_TRESID_SCALED_BYB .or. &
407
HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYB ) then
408
rhsnorm = normfun( HUTI_NDIM, B, 1 )
409
end if
410
if ( HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYPRECB ) then
411
call pcondlsubr( P, B, ipar )
412
precrhsnorm = normfun( HUTI_NDIM, P, 1 )
413
end if
414
415
! Generate vector X if needed
416
417
if ( HUTI_INITIALX .eq. HUTI_RANDOMX ) then
418
call huti_drandvec ( X, ipar )
419
else if ( HUTI_INITIALX .ne. HUTI_USERSUPPLIEDX ) then
420
X = 1
421
end if
422
423
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
424
call matvecsubr( X, R, ipar )
425
R = B - R
426
VTLD = R
427
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
428
call pcondlsubr( Y, VTLD, ipar )
429
430
WTLD = R
431
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
432
call pcondrsubr( Z, WTLD, ipar )
433
434
rho = normfun( HUTI_NDIM, Y, 1 )
435
psi = normfun( HUTI_NDIM, Z, 1 )
436
oldgamma = 1
437
eta = -1
438
439
!
440
! This is where the loop starts (that is we continue from here after
441
! the first iteration)
442
!
443
444
300 continue
445
446
if (( rho .eq. 0 ) .or. ( psi .eq. 0 )) then
447
HUTI_INFO = HUTI_QMR_RHO_PSI
448
go to 1000
449
end if
450
451
V = VTLD / rho
452
Y = Y / rho
453
W = WTLD / psi
454
Z = Z / psi
455
delta = dotprodfun( HUTI_NDIM, Z, 1, Y, 1 )
456
457
if ( delta .eq. 0 ) then
458
HUTI_INFO = HUTI_QMR_DELTA
459
go to 1000
460
end if
461
462
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
463
call pcondrsubr( YTLD, Y, ipar )
464
465
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
466
call pcondlsubr( ZTLD, Z, ipar )
467
468
if ( iter_count .eq. 1 ) then
469
P = YTLD
470
Q = ZTLD
471
else
472
P = YTLD - ((psi * delta)/epsilon) * P
473
Q = ZTLD - ((rho * delta)/epsilon) * Q
474
end if
475
476
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
477
call matvecsubr( P, PTLD, ipar )
478
epsilon = dotprodfun( HUTI_NDIM, Q, 1, PTLD, 1 )
479
if ( epsilon .eq. 0 ) then
480
HUTI_INFO = HUTI_QMR_EPSILON
481
go to 1000
482
end if
483
484
beta = epsilon / delta
485
if ( beta .eq. 0 ) then
486
HUTI_INFO = HUTI_QMR_BETA
487
go to 1000
488
end if
489
490
VTLD = PTLD - beta * V
491
492
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
493
call pcondlsubr( Y, VTLD, ipar )
494
495
rhonext = normfun( ndim, Y, 1 )
496
497
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
498
call matvecsubr( Q, WTLD, ipar )
499
500
WTLD = WTLD - beta * W
501
502
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
503
call pcondrsubr( Z, WTLD, ipar )
504
505
psi = normfun( HUTI_NDIM, Z, 1 )
506
theta = rhonext / (oldgamma * abs( beta ))
507
gamma = 1 / sqrt( 1 + theta * theta )
508
if ( gamma .eq. 0 ) then
509
HUTI_INFO = HUTI_QMR_GAMMA
510
go to 1000
511
end if
512
513
eta = -1 * ( eta * rho * gamma * gamma ) / ( beta * oldgamma * oldgamma )
514
515
if ( iter_count .eq. 1 ) then
516
D = eta * P
517
S = eta * PTLD
518
else
519
D = eta * P + ( oldtheta * gamma ) * ( oldtheta * gamma ) * D
520
S = eta * PTLD + ( oldtheta * gamma ) * ( oldtheta * gamma ) * S
521
end if
522
X = X + D
523
R = R - S
524
525
!
526
! Check the convergence against selected stopping criterion
527
!
528
529
select case (HUTI_STOPC)
530
case (HUTI_TRUERESIDUAL)
531
call matvecsubr( X, YTLD, ipar )
532
YTLD = YTLD - B
533
residual = normfun( HUTI_NDIM, YTLD, 1 )
534
case (HUTI_TRESID_SCALED_BYB)
535
call matvecsubr( X, YTLD, ipar )
536
YTLD = YTLD - B
537
residual = normfun( HUTI_NDIM, YTLD, 1 ) / rhsnorm
538
case (HUTI_PSEUDORESIDUAL)
539
residual = normfun( HUTI_NDIM, R, 1 )
540
case (HUTI_PRESID_SCALED_BYB)
541
residual = normfun( HUTI_NDIM, R, 1 ) / rhsnorm
542
case (HUTI_PRESID_SCALED_BYPRECB)
543
residual = normfun( HUTI_NDIM, R, 1 ) / precrhsnorm
544
case (HUTI_XDIFF_NORM)
545
residual = normfun( HUTI_NDIM, D, 1 )
546
case (HUTI_USUPPLIED_STOPC)
547
residual = stopcfun( X, B, R, ipar, dpar )
548
case default
549
call matvecsubr( X, YTLD, ipar )
550
YTLD = YTLD - B
551
residual = normfun( HUTI_NDIM, YTLD, 1 )
552
end select
553
554
!
555
! Print debugging output if desired
556
!
557
558
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
559
if ( mod(iter_count, HUTI_DBUGLVL) .eq. 0 ) then
560
write (*, '(I8, E11.4)') iter_count, residual
561
end if
562
end if
563
564
if ( residual .lt. HUTI_TOLERANCE ) then
565
HUTI_INFO = HUTI_CONVERGENCE
566
go to 1000
567
end if
568
569
IF( residual /= residual .OR. residual > HUTI_MAXTOLERANCE ) THEN
570
HUTI_INFO = HUTI_DIVERGENCE
571
GOTO 1000
572
END IF
573
574
rho = rhonext
575
oldgamma = gamma
576
oldtheta = theta
577
578
!
579
! Return back to the iteration loop (without initialization)
580
!
581
582
iter_count = iter_count + 1
583
if ( iter_count .gt. HUTI_MAXIT ) then
584
HUTI_INFO = HUTI_MAXITER
585
go to 1000
586
end if
587
588
go to 300
589
590
!
591
! This is where we exit last time (after enough iterations or breakdown)
592
!
593
594
1000 continue
595
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
596
write (*, '(I8, E11.4)') iter_count, residual
597
end if
598
599
HUTI_ITERS = iter_count
600
return
601
602
! End of execution
603
!*********************************************************************
604
605
end subroutine huti_dqmrsolv
606
607
!*********************************************************************
608
609
610
!*************************************************************************
611
!*************************************************************************
612
! Complex version
613
!*************************************************************************
614
!*************************************************************************
615
616
subroutine huti_cqmrsolv ( ndim, wrkdim, xvec, rhsvec, &
617
ipar, dpar, work, matvecsubr, pcondlsubr, &
618
pcondrsubr, dotprodfun, normfun, stopcfun )
619
use huti_interfaces
620
implicit none
621
622
procedure( mv_iface_c ), pointer :: matvecsubr
623
procedure( pc_iface_c ), pointer :: pcondlsubr
624
procedure( pc_iface_c ), pointer :: pcondrsubr
625
procedure( dotp_iface_c ), pointer :: dotprodfun
626
procedure( norm_iface_c ), pointer :: normfun
627
procedure( stopc_iface_c ), pointer :: stopcfun
628
629
! Parameters
630
631
integer :: ndim, wrkdim
632
complex, dimension(ndim) :: xvec, rhsvec
633
integer, dimension(HUTI_IPAR_DFLTSIZE) :: ipar
634
double precision, dimension(HUTI_DPAR_DFLTSIZE) :: dpar
635
complex, dimension(ndim,wrkdim) :: work
636
637
! Local variables
638
639
complex :: beta, gamma, oldgamma, delta, rho, rhonext
640
complex :: psi, theta, oldtheta, eta, epsilon
641
integer iter_count
642
real :: residual, rhsnorm, precrhsnorm
643
644
!
645
! End of variable declarations
646
!*********************************************************************
647
648
!*********************************************************************
649
! The actual QMR begins here (look the pseudo code in the
650
! "Templates.."-book on page 24)
651
!
652
! First the initialization part
653
!
654
655
iter_count = 1
656
657
! Norms of right-hand side vector are used in convergence tests
658
659
if ( HUTI_STOPC .eq. HUTI_TRESID_SCALED_BYB .or. &
660
HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYB ) then
661
rhsnorm = normfun( HUTI_NDIM, B, 1 )
662
end if
663
if ( HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYPRECB ) then
664
call pcondlsubr( P, B, ipar )
665
precrhsnorm = normfun( HUTI_NDIM, P, 1 )
666
end if
667
668
! Generate vector X if needed
669
670
if ( HUTI_INITIALX .eq. HUTI_RANDOMX ) then
671
call huti_crandvec ( X, ipar )
672
else if ( HUTI_INITIALX .ne. HUTI_USERSUPPLIEDX ) then
673
X = 1
674
end if
675
676
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
677
call matvecsubr( X, R, ipar )
678
R = B - R
679
VTLD = R
680
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
681
call pcondlsubr( Y, VTLD, ipar )
682
683
WTLD = R
684
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
685
call pcondrsubr( Z, WTLD, ipar )
686
687
rho = normfun( HUTI_NDIM, Y, 1 )
688
psi = normfun( HUTI_NDIM, Z, 1 )
689
oldgamma = 1
690
eta = -1
691
692
!
693
! This is where the loop starts (that is we continue from here after
694
! the first iteration)
695
!
696
697
300 continue
698
699
if (( rho .eq. 0 ) .or. ( psi .eq. 0 )) then
700
HUTI_INFO = HUTI_QMR_RHO_PSI
701
go to 1000
702
end if
703
704
V = VTLD / rho
705
Y = Y / rho
706
W = WTLD / psi
707
Z = Z / psi
708
delta = dotprodfun( HUTI_NDIM, Z, 1, Y, 1 )
709
710
if ( delta .eq. 0 ) then
711
HUTI_INFO = HUTI_QMR_DELTA
712
go to 1000
713
end if
714
715
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
716
call pcondrsubr( YTLD, Y, ipar )
717
718
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
719
call pcondlsubr( ZTLD, Z, ipar )
720
721
if ( iter_count .eq. 1 ) then
722
P = YTLD
723
Q = ZTLD
724
else
725
P = YTLD - ((psi * delta)/epsilon) * P
726
Q = ZTLD - ((rho * delta)/epsilon) * Q
727
end if
728
729
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
730
call matvecsubr( P, PTLD, ipar )
731
epsilon = dotprodfun( HUTI_NDIM, Q, 1, PTLD, 1 )
732
if ( epsilon .eq. 0 ) then
733
HUTI_INFO = HUTI_QMR_EPSILON
734
go to 1000
735
end if
736
737
beta = epsilon / delta
738
if ( beta .eq. 0 ) then
739
HUTI_INFO = HUTI_QMR_BETA
740
go to 1000
741
end if
742
743
VTLD = PTLD - beta * V
744
745
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
746
call pcondlsubr( Y, VTLD, ipar )
747
748
rhonext = normfun( ndim, Y, 1 )
749
750
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
751
call matvecsubr( Q, WTLD, ipar )
752
753
WTLD = WTLD - beta * W
754
755
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
756
call pcondrsubr( Z, WTLD, ipar )
757
758
psi = normfun( HUTI_NDIM, Z, 1 )
759
theta = rhonext / (oldgamma * abs( beta ))
760
gamma = 1 / sqrt( 1 + theta * theta )
761
if ( gamma .eq. 0 ) then
762
HUTI_INFO = HUTI_QMR_GAMMA
763
go to 1000
764
end if
765
766
eta = -1 * ( eta * rho * gamma * gamma ) / ( beta * oldgamma * oldgamma )
767
768
if ( iter_count .eq. 1 ) then
769
D = eta * P
770
S = eta * PTLD
771
else
772
D = eta * P + ( oldtheta * gamma ) * ( oldtheta * gamma ) * D
773
S = eta * PTLD + ( oldtheta * gamma ) * ( oldtheta * gamma ) * S
774
end if
775
X = X + D
776
R = R - S
777
778
!
779
! Check the convergence against selected stopping criterion
780
!
781
782
select case (HUTI_STOPC)
783
case (HUTI_TRUERESIDUAL)
784
call matvecsubr( X, YTLD, ipar )
785
YTLD = YTLD - B
786
residual = normfun( HUTI_NDIM, YTLD, 1 )
787
case (HUTI_TRESID_SCALED_BYB)
788
call matvecsubr( X, YTLD, ipar )
789
YTLD = YTLD - B
790
residual = normfun( HUTI_NDIM, YTLD, 1 ) / rhsnorm
791
case (HUTI_PSEUDORESIDUAL)
792
residual = normfun( HUTI_NDIM, R, 1 )
793
case (HUTI_PRESID_SCALED_BYB)
794
residual = normfun( HUTI_NDIM, R, 1 ) / rhsnorm
795
case (HUTI_PRESID_SCALED_BYPRECB)
796
residual = normfun( HUTI_NDIM, R, 1 ) / precrhsnorm
797
case (HUTI_XDIFF_NORM)
798
residual = normfun( HUTI_NDIM, D, 1 )
799
case (HUTI_USUPPLIED_STOPC)
800
residual = stopcfun( X, B, R, ipar, dpar )
801
case default
802
call matvecsubr( X, YTLD, ipar )
803
YTLD = YTLD - B
804
residual = normfun( HUTI_NDIM, YTLD, 1 )
805
end select
806
807
!
808
! Print debugging output if desired
809
!
810
811
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
812
if ( mod(iter_count, HUTI_DBUGLVL) .eq. 0 ) then
813
write (*, '(I8, E11.4)') iter_count, residual
814
end if
815
end if
816
817
if ( residual .lt. HUTI_TOLERANCE ) then
818
HUTI_INFO = HUTI_CONVERGENCE
819
go to 1000
820
end if
821
822
IF( residual /= residual .OR. residual > HUTI_MAXTOLERANCE ) THEN
823
HUTI_INFO = HUTI_DIVERGENCE
824
GOTO 1000
825
END IF
826
827
rho = rhonext
828
oldgamma = gamma
829
oldtheta = theta
830
831
!
832
! Return back to the iteration loop (without initialization)
833
!
834
835
iter_count = iter_count + 1
836
if ( iter_count .gt. HUTI_MAXIT ) then
837
HUTI_INFO = HUTI_MAXITER
838
go to 1000
839
end if
840
841
go to 300
842
843
!
844
! This is where we exit last time (after enough iterations or breakdown)
845
!
846
847
1000 continue
848
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
849
write (*, '(I8, E11.4)') iter_count, residual
850
end if
851
852
HUTI_ITERS = iter_count
853
return
854
855
! End of execution
856
!*********************************************************************
857
858
end subroutine huti_cqmrsolv
859
860
!*********************************************************************
861
862
863
!*************************************************************************
864
!*************************************************************************
865
! Double complex version
866
!*************************************************************************
867
!*************************************************************************
868
869
subroutine huti_zqmrsolv ( ndim, wrkdim, xvec, rhsvec, &
870
ipar, dpar, work, matvecsubr, pcondlsubr, &
871
pcondrsubr, dotprodfun, normfun, stopcfun )
872
use huti_interfaces
873
implicit none
874
875
procedure( mv_iface_z ), pointer :: matvecsubr
876
procedure( pc_iface_z ), pointer :: pcondlsubr
877
procedure( pc_iface_z ), pointer :: pcondrsubr
878
procedure( dotp_iface_z ), pointer :: dotprodfun
879
procedure( norm_iface_z ), pointer :: normfun
880
procedure( stopc_iface_z ), pointer :: stopcfun
881
882
! Parameters
883
884
integer :: ndim, wrkdim
885
double complex, dimension(ndim) :: xvec, rhsvec
886
integer, dimension(HUTI_IPAR_DFLTSIZE) :: ipar
887
double precision, dimension(HUTI_DPAR_DFLTSIZE) :: dpar
888
double complex, dimension(ndim,wrkdim) :: work
889
890
! Local variables
891
892
double complex :: beta, gamma, oldgamma, delta, rho, rhonext
893
double complex :: psi, theta, oldtheta, eta, epsilon
894
integer iter_count
895
double precision :: residual, rhsnorm, precrhsnorm
896
897
!
898
! End of variable declarations
899
!*********************************************************************
900
901
!*********************************************************************
902
! The actual QMR begins here (look the pseudo code in the
903
! "Templates.."-book on page 24)
904
!
905
! First the initialization part
906
!
907
908
iter_count = 1
909
910
! Norms of right-hand side vector are used in convergence tests
911
912
if ( HUTI_STOPC .eq. HUTI_TRESID_SCALED_BYB .or. &
913
HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYB ) then
914
rhsnorm = normfun( HUTI_NDIM, B, 1 )
915
end if
916
if ( HUTI_STOPC .eq. HUTI_PRESID_SCALED_BYPRECB ) then
917
call pcondlsubr( P, B, ipar )
918
precrhsnorm = normfun( HUTI_NDIM, P, 1 )
919
end if
920
921
! Generate vector X if needed
922
923
if ( HUTI_INITIALX .eq. HUTI_RANDOMX ) then
924
call huti_zrandvec ( X, ipar )
925
else if ( HUTI_INITIALX .ne. HUTI_USERSUPPLIEDX ) then
926
X = 1
927
end if
928
929
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
930
call matvecsubr( X, R, ipar )
931
R = B - R
932
VTLD = R
933
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
934
call pcondlsubr( Y, VTLD, ipar )
935
936
WTLD = R
937
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
938
call pcondrsubr( Z, WTLD, ipar )
939
940
rho = normfun( HUTI_NDIM, Y, 1 )
941
psi = normfun( HUTI_NDIM, Z, 1 )
942
oldgamma = 1
943
eta = -1
944
945
!
946
! This is where the loop starts (that is we continue from here after
947
! the first iteration)
948
!
949
950
300 continue
951
952
if (( rho .eq. 0 ) .or. ( psi .eq. 0 )) then
953
HUTI_INFO = HUTI_QMR_RHO_PSI
954
go to 1000
955
end if
956
957
V = VTLD / rho
958
Y = Y / rho
959
W = WTLD / psi
960
Z = Z / psi
961
delta = dotprodfun( HUTI_NDIM, Z, 1, Y, 1 )
962
963
if ( delta .eq. 0 ) then
964
HUTI_INFO = HUTI_QMR_DELTA
965
go to 1000
966
end if
967
968
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
969
call pcondrsubr( YTLD, Y, ipar )
970
971
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
972
call pcondlsubr( ZTLD, Z, ipar )
973
974
if ( iter_count .eq. 1 ) then
975
P = YTLD
976
Q = ZTLD
977
else
978
P = YTLD - ((psi * delta)/epsilon) * P
979
Q = ZTLD - ((rho * delta)/epsilon) * Q
980
end if
981
982
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
983
call matvecsubr( P, PTLD, ipar )
984
epsilon = dotprodfun( HUTI_NDIM, Q, 1, PTLD, 1 )
985
if ( epsilon .eq. 0 ) then
986
HUTI_INFO = HUTI_QMR_EPSILON
987
go to 1000
988
end if
989
990
beta = epsilon / delta
991
if ( beta .eq. 0 ) then
992
HUTI_INFO = HUTI_QMR_BETA
993
go to 1000
994
end if
995
996
VTLD = PTLD - beta * V
997
998
HUTI_EXTOP_MATTYPE = HUTI_MAT_NOTTRPSED
999
call pcondlsubr( Y, VTLD, ipar )
1000
1001
rhonext = normfun( ndim, Y, 1 )
1002
1003
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
1004
call matvecsubr( Q, WTLD, ipar )
1005
1006
WTLD = WTLD - beta * W
1007
1008
HUTI_EXTOP_MATTYPE = HUTI_MAT_TRPSED
1009
call pcondrsubr( Z, WTLD, ipar )
1010
1011
psi = normfun( HUTI_NDIM, Z, 1 )
1012
theta = rhonext / (oldgamma * abs( beta ))
1013
gamma = 1 / sqrt( 1 + theta * theta )
1014
if ( gamma .eq. 0 ) then
1015
HUTI_INFO = HUTI_QMR_GAMMA
1016
go to 1000
1017
end if
1018
1019
eta = -1 * ( eta * rho * gamma * gamma ) / ( beta * oldgamma * oldgamma )
1020
1021
if ( iter_count .eq. 1 ) then
1022
D = eta * P
1023
S = eta * PTLD
1024
else
1025
D = eta * P + ( oldtheta * gamma ) * ( oldtheta * gamma ) * D
1026
S = eta * PTLD + ( oldtheta * gamma ) * ( oldtheta * gamma ) * S
1027
end if
1028
X = X + D
1029
R = R - S
1030
1031
!
1032
! Check the convergence against selected stopping criterion
1033
!
1034
1035
select case (HUTI_STOPC)
1036
case (HUTI_TRUERESIDUAL)
1037
call matvecsubr( X, YTLD, ipar )
1038
YTLD = YTLD - B
1039
residual = normfun( HUTI_NDIM, YTLD, 1 )
1040
case (HUTI_TRESID_SCALED_BYB)
1041
call matvecsubr( X, YTLD, ipar )
1042
YTLD = YTLD - B
1043
residual = normfun( HUTI_NDIM, YTLD, 1 ) / rhsnorm
1044
case (HUTI_PSEUDORESIDUAL)
1045
residual = normfun( HUTI_NDIM, R, 1 )
1046
case (HUTI_PRESID_SCALED_BYB)
1047
residual = normfun( HUTI_NDIM, R, 1 ) / rhsnorm
1048
case (HUTI_PRESID_SCALED_BYPRECB)
1049
residual = normfun( HUTI_NDIM, R, 1 ) / precrhsnorm
1050
case (HUTI_XDIFF_NORM)
1051
residual = normfun( HUTI_NDIM, D, 1 )
1052
case (HUTI_USUPPLIED_STOPC)
1053
residual = stopcfun( X, B, R, ipar, dpar )
1054
case default
1055
call matvecsubr( X, YTLD, ipar )
1056
YTLD = YTLD - B
1057
residual = normfun( HUTI_NDIM, YTLD, 1 )
1058
end select
1059
1060
!
1061
! Print debugging output if desired
1062
!
1063
1064
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
1065
if ( mod(iter_count, HUTI_DBUGLVL) .eq. 0 ) then
1066
write (*, '(I8, E11.4)') iter_count, residual
1067
end if
1068
end if
1069
1070
if ( residual .lt. HUTI_TOLERANCE ) then
1071
HUTI_INFO = HUTI_CONVERGENCE
1072
go to 1000
1073
end if
1074
1075
IF( residual /= residual .OR. residual > HUTI_MAXTOLERANCE ) THEN
1076
HUTI_INFO = HUTI_DIVERGENCE
1077
GOTO 1000
1078
END IF
1079
1080
rho = rhonext
1081
oldgamma = gamma
1082
oldtheta = theta
1083
1084
!
1085
! Return back to the iteration loop (without initialization)
1086
!
1087
1088
iter_count = iter_count + 1
1089
if ( iter_count .gt. HUTI_MAXIT ) then
1090
HUTI_INFO = HUTI_MAXITER
1091
go to 1000
1092
end if
1093
1094
go to 300
1095
1096
!
1097
! This is where we exit last time (after enough iterations or breakdown)
1098
!
1099
1100
1000 continue
1101
if ( HUTI_DBUGLVL .ne. HUTI_NO_DEBUG ) then
1102
write (*, '(I8, E11.4)') iter_count, residual
1103
end if
1104
1105
HUTI_ITERS = iter_count
1106
return
1107
1108
! End of execution
1109
!*********************************************************************
1110
1111
end subroutine huti_zqmrsolv
1112
1113
!*********************************************************************
1114
1115
1116
end module huti_qmr
1117
1118