27 public :: hecmwst_saamg_blockdiag
36 public :: hecmwst_saamg_chebyshev
41 type hecmwst_saamg_blockdiag
42 integer(kind=kint) :: nnode = 0
43 integer(kind=kint) :: nb = 0
44 real(kind=
kreal),
allocatable :: dblk(:)
45 real(kind=
kreal),
allocatable :: inv(:)
46 end type hecmwst_saamg_blockdiag
49 type hecmwst_saamg_chebyshev
50 integer(kind=kint) :: deg = 2
51 real(kind=
kreal) :: theta = 0.0d0
52 real(kind=
kreal) :: delta = 0.0d0
53 real(kind=
kreal) :: sigma = 0.0d0
54 end type hecmwst_saamg_chebyshev
72 type(hecmwst_saamg_bcsr),
intent(in) :: a
73 type(hecmwst_saamg_blockdiag),
intent(out) :: d
74 integer(kind=kint) :: nb, nnode, inode, off, t, info, astat
77 if (nb <= 0 .or. a%mb /= nb .or. mod(a%n, nb) /= 0)
then
78 write(*,*)
'hecmw_saamg_blockdiag_setup: A not square-blocked (nb,mb)=', nb, a%mb
84 d%nb = nb; d%nnode = nnode
85 allocate(d%dblk(nb*nb*nnode), d%inv(nb*nb*nnode), stat=astat)
94 do t = a%browptr(inode), a%browptr(inode+1)-1
95 if (a%bcol(t) == inode)
then
96 d%dblk(off+1:off+nb*nb) = a%bval((t-1)*nb*nb+1:t*nb*nb)
100 call block_inverse(nb, d%dblk(off+1:off+nb*nb), d%inv(off+1:off+nb*nb), info)
102 write(*,
'(a,i0)')
'hecmw_saamg_blockdiag_setup: singular diagonal block at node ', inode
117 subroutine block_inverse(nb, a, ainv, info)
119 integer(kind=kint),
intent(in) :: nb
120 real(kind=
kreal),
intent(in) :: a(nb*nb)
121 real(kind=
kreal),
intent(out) :: ainv(nb*nb)
122 integer(kind=kint),
intent(out) :: info
123 real(kind=
kreal) :: det, idet, piv, f, aug(nb, 2*nb)
124 integer(kind=kint) :: i, j, k, p
128 if (a(1) == 0.0d0) then; info = 1; return;
end if
129 ainv(1) = 1.0d0 / a(1)
131 det = a(1)*a(4) - a(2)*a(3)
132 if (det == 0.0d0) then; info = 1; return;
end if
134 ainv(1) = a(4)*idet; ainv(2) = -a(2)*idet
135 ainv(3) = -a(3)*idet; ainv(4) = a(1)*idet
137 det = a(1)*(a(5)*a(9)-a(8)*a(6)) - a(4)*(a(2)*a(9)-a(8)*a(3)) + a(7)*(a(2)*a(6)-a(5)*a(3))
138 if (det == 0.0d0) then; info = 1; return;
end if
140 ainv(1) = (a(5)*a(9)-a(8)*a(6))*idet
141 ainv(2) = (a(8)*a(3)-a(2)*a(9))*idet
142 ainv(3) = (a(2)*a(6)-a(5)*a(3))*idet
143 ainv(4) = (a(7)*a(6)-a(4)*a(9))*idet
144 ainv(5) = (a(1)*a(9)-a(7)*a(3))*idet
145 ainv(6) = (a(4)*a(3)-a(1)*a(6))*idet
146 ainv(7) = (a(4)*a(8)-a(7)*a(5))*idet
147 ainv(8) = (a(7)*a(2)-a(1)*a(8))*idet
148 ainv(9) = (a(1)*a(5)-a(4)*a(2))*idet
153 aug(i, j) = a((j-1)*nb + i)
161 if (abs(aug(i,k)) > abs(aug(p,k))) p = i
163 if (aug(p,k) == 0.0d0) then; info = 1; return;
end if
166 f = aug(k,j); aug(k,j) = aug(p,j); aug(p,j) = f
171 aug(k,j) = aug(k,j) / piv
176 if (f == 0.0d0) cycle
178 aug(i,j) = aug(i,j) - f*aug(k,j)
184 ainv((j-1)*nb + i) = aug(i, nb+j)
188 end subroutine block_inverse
193 type(hecmwst_saamg_blockdiag),
intent(in) :: d
194 real(kind=
kreal),
intent(in) :: x(:)
195 real(kind=
kreal),
intent(out) :: y(:)
196 integer(kind=kint) :: inode, base, ii, jj, off, nb
197 real(kind=
kreal) :: s
207 do inode = 1, d%nnode
209 off = (inode-1)*nb*nb
215 s = s + d%inv(off + (jj-1)*nb + ii) * x(base+jj)
232 type(hecmwst_saamg_blockdiag),
intent(in) :: d
233 type(hecmwst_saamg_bcsr),
intent(in) :: c
234 type(hecmwst_saamg_bcsr),
intent(out) :: dc
235 integer(kind=kint) :: nb, mb, inode, off, t, b0, ii, jj, cc, astat
236 real(kind=
kreal) :: s
239 if (c%nb /= nb .or. c%nbrow /= d%nnode)
then
240 write(*,*)
'hecmw_saamg_blockdiag_apply_bcsr: block-row mismatch', c%nb, nb, &
248 dc%n = c%n; dc%ncol = c%ncol; dc%nb = nb; dc%mb = mb
249 dc%nbrow = c%nbrow; dc%nbcol = c%nbcol; dc%nnzb = c%nnzb
250 allocate(dc%browptr(c%nbrow+1), dc%bcol(c%nnzb), dc%bval(nb*mb*c%nnzb), stat=astat)
252 dc%browptr = c%browptr; dc%bcol = c%bcol
255 do inode = 1, c%nbrow
256 off = (inode-1)*nb*nb
257 do t = c%browptr(inode), c%browptr(inode+1)-1
263 s = s + d%inv(off + (jj-1)*nb + ii) * c%bval(b0 + (cc-1)*nb + jj)
265 dc%bval(b0 + (cc-1)*nb + ii) = s
279 type(hecmwst_saamg_blockdiag),
intent(in) :: d
280 type(hecmwst_saamg_bcsr),
intent(inout) :: c
281 integer(kind=kint) :: nb, mb, inode, off, t, b0, ii, jj, cc
282 real(kind=
kreal) :: tmp(d%nb), s
284 if (c%nb /= nb .or. c%nbrow /= d%nnode)
then
285 write(*,*)
'hecmw_saamg_blockdiag_apply_bcsr_inplace: block-row mismatch', &
286 c%nb, nb, c%nbrow, d%nnode
290 do inode = 1, c%nbrow
291 off = (inode-1)*nb*nb
292 do t = c%browptr(inode), c%browptr(inode+1)-1
296 tmp(jj) = c%bval(b0 + (cc-1)*nb + jj)
301 s = s + d%inv(off + (jj-1)*nb + ii) * tmp(jj)
303 c%bval(b0 + (cc-1)*nb + ii) = s
314 type(hecmwst_saamg_blockdiag),
intent(in) :: d
315 real(kind=
kreal),
intent(in) :: x(:)
316 real(kind=
kreal),
intent(out) :: y(:)
317 integer(kind=kint) :: inode, base, ii, jj, off
318 real(kind=
kreal) :: s
321 do inode = 1, d%nnode
322 base = (inode-1)*d%nb
323 off = (inode-1)*d%nb*d%nb
327 s = s + d%dblk(off + (jj-1)*d%nb + ii) * x(base+jj)
337 type(hecmwst_saamg_blockdiag),
intent(inout) :: d
338 if (
allocated(d%dblk))
deallocate(d%dblk)
339 if (
allocated(d%inv))
deallocate(d%inv)
340 d%nnode = 0; d%nb = 0
353 real(kind=
kreal),
intent(in) :: diag(:), offd(:)
354 integer(kind=kint),
intent(in) :: m
355 real(kind=
kreal) :: lmax
356 real(kind=
kreal),
allocatable :: d(:), e(:)
357 integer(kind=kint) :: info
358 #ifdef HECMW_WITH_LAPACK
360 if (m <= 1) then; lmax = diag(1); return;
end if
361 allocate(d(m), e(m-1))
362 d(1:m) = diag(1:m); e(1:m-1) = offd(1:m-1)
363 call dsterf(m, d, e, info)
364 if (info == 0) then; lmax = d(m); else; lmax = maxval(diag(1:m));
end if
369 lmax = maxval(diag(1:m))
382 type(hecmwst_saamg_bcsr),
intent(in) :: a
383 type(hecmwst_saamg_blockdiag),
intent(in) :: d
384 integer(kind=kint),
intent(in) :: niter
385 real(kind=
kreal) :: lambda
386 real(kind=
kreal),
allocatable :: q(:), qp(:), w(:), aq(:), dv(:), alpha(:), beta(:)
387 real(kind=
kreal) :: qdq, wdw, bprev
388 integer(kind=kint) :: j, i, m
389 integer(kind=8) :: seed
391 allocate(q(a%n), qp(a%n), w(a%n), aq(a%n), dv(a%n), alpha(niter), beta(niter))
394 seed = 88172645463325252_8
396 seed = seed*6364136223846793005_8 + 1442695040888963407_8
397 q(i) = real(seed,
kreal)/9.223372036854776d18
401 if (qdq <= 0.0d0) then; lambda = 0.0d0;
deallocate(q,qp,w,aq,dv,alpha,beta); return;
end if
402 q = q / sqrt(qdq); qp = 0.0d0; bprev = 0.0d0; m = 0
407 alpha(j) = dot_product(aq, q)
408 w = w - alpha(j)*q - bprev*qp
411 if (wdw <= 0.0d0)
exit
414 qp = q; bprev = beta(j); q = w / beta(j)
418 deallocate(q, qp, w, aq, dv, alpha, beta)
429 real(kind=
kreal),
intent(in) :: lambda_hat
430 integer(kind=kint),
intent(in) :: deg
431 real(kind=
kreal),
intent(in) :: alpha
432 type(hecmwst_saamg_chebyshev),
intent(out) :: cheb
433 real(kind=
kreal) :: lmax, lmin
434 lmax = 1.1d0 * lambda_hat
437 cheb%theta = 0.5d0*(lmax + lmin)
438 cheb%delta = 0.5d0*(lmax - lmin)
439 cheb%sigma = cheb%theta / cheb%delta
446 type(hecmwst_saamg_bcsr),
intent(in) :: a
447 type(hecmwst_saamg_blockdiag),
intent(in) :: d
448 type(hecmwst_saamg_chebyshev),
intent(in) :: cheb
449 real(kind=
kreal),
intent(in) :: b(:)
450 real(kind=
kreal),
intent(inout) :: x(:)
451 logical,
intent(in) :: zero_init
452 real(kind=
kreal),
allocatable :: r(:), p(:), dr(:), ap(:)
453 real(kind=
kreal) :: rho, rho2, c1, c2
454 integer(kind=kint) :: it, n
457 allocate(r(n), p(n), dr(n), ap(n))
469 rho = 1.0d0 / cheb%sigma
475 rho2 = 1.0d0 / (2.0d0*cheb%sigma - rho)
478 c2 = 2.0d0 * rho2 / cheb%delta
483 deallocate(r, p, dr, ap)
Smoothed Aggregation AMG preconditioner : lightweight comm table.
subroutine, public hecmw_saamg_check_alloc(ier, what)
Report a failed allocation (stat /= 0) with a clear message and a collective abort,...
subroutine, public hecmw_saamg_abort(msg)
Fatal-error termination with a clear message. Under MPI this is a COLLECTIVE abort (hecmw_abort -> MP...
Smoothed Aggregation AMG preconditioner : internal block-CSR matrix.
subroutine, public hecmw_saamg_bcsr_free(A)
Release the storage held by a hecmwST_saamg_bcsr.
subroutine, public hecmw_saamg_matvec(A, x, y)
Sparse matrix-vector product : y = A x.
Smoothed Aggregation AMG preconditioner : smoother building blocks.
subroutine, public hecmw_saamg_cheb_setup(lambda_hat, deg, alpha, cheb)
Set Chebyshev interval [lmax/alpha, lmax] with lmax = 1.1 * lambda_hat. lambda_hat is the (already sa...
subroutine, public hecmw_saamg_blockdiag_apply_bcsr_inplace(D, C)
Apply C <- D^{-1} C in place (each nb x mb block solved against the node's LU). Same as blockdiag_app...
real(kind=kreal) function, public hecmw_saamg_lanczos_lambda_max(A, D, niter)
Estimate lambda_max(D^{-1}A) by D-inner-product Lanczos. M = D^{-1}A is self-adjoint in <u,...
subroutine, public hecmw_saamg_blockdiag_apply_bcsr(D, C, DC)
Apply DC = D^{-1} C block-row-wise to a block-CSR matrix C (reusing the stored block LU)....
subroutine, public hecmw_saamg_cheb_apply_local(A, D, cheb, b, x, zero_init)
Apply the Chebyshev smoother: x <- x + p_k(D^{-1}A)(b - A x). zero_init = .true. assumes x=0 on entry...
subroutine, public hecmw_saamg_blockdiag_matvec(D, x, y)
Apply y = D x (block-wise dense matvec using the original blocks).
subroutine, public hecmw_saamg_blockdiag_apply(D, x, y)
Apply y = D^{-1} x (block-wise small dense matmul against the stored inverse).
subroutine, public hecmw_saamg_blockdiag_free(D)
subroutine, public hecmw_saamg_blockdiag_setup(A, D)
Extract the nb x nb diagonal blocks of A, keep them, and store the explicit inverse D_i^{-1} of each ...
real(kind=kreal) function, public hecmw_saamg_tridiag_max_eig(diag, offd, m)
Largest eigenvalue of a symmetric tridiagonal matrix (diagonal diag(1:m), sub/super-diagonal offd(1:m...
Smoothed Aggregation AMG preconditioner : kind parameters.
integer(kind=4), parameter kreal