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
75 logical :: square_blocked
78 square_blocked = nb > 0 .and. a%mb == nb
79 if (square_blocked) square_blocked = mod(a%n, nb) == 0
80 if (.not. square_blocked)
then
81 write(*,*)
'hecmw_saamg_blockdiag_setup: A not square-blocked (nb,mb)=', nb, a%mb
87 d%nb = nb; d%nnode = nnode
88 allocate(d%dblk(nb*nb*nnode), d%inv(nb*nb*nnode), stat=astat)
97 do t = a%browptr(inode), a%browptr(inode+1)-1
98 if (a%bcol(t) == inode)
then
99 d%dblk(off+1:off+nb*nb) = a%bval((t-1)*nb*nb+1:t*nb*nb)
103 call block_inverse(nb, d%dblk(off+1:off+nb*nb), d%inv(off+1:off+nb*nb), info)
106 write(*,
'(a,i0)')
'hecmw_saamg_blockdiag_setup: singular diagonal block at node ', inode
122 subroutine block_inverse(nb, a, ainv, info)
124 integer(kind=kint),
intent(in) :: nb
125 real(kind=
kreal),
intent(in) :: a(nb*nb)
126 real(kind=
kreal),
intent(out) :: ainv(nb*nb)
127 integer(kind=kint),
intent(out) :: info
128 real(kind=
kreal) :: det, idet, piv, f, aug(nb, 2*nb)
129 integer(kind=kint) :: i, j, k, p
133 if (a(1) == 0.0d0) then; info = 1; return;
end if
134 ainv(1) = 1.0d0 / a(1)
136 det = a(1)*a(4) - a(2)*a(3)
137 if (det == 0.0d0) then; info = 1; return;
end if
139 ainv(1) = a(4)*idet; ainv(2) = -a(2)*idet
140 ainv(3) = -a(3)*idet; ainv(4) = a(1)*idet
142 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))
143 if (det == 0.0d0) then; info = 1; return;
end if
145 ainv(1) = (a(5)*a(9)-a(8)*a(6))*idet
146 ainv(2) = (a(8)*a(3)-a(2)*a(9))*idet
147 ainv(3) = (a(2)*a(6)-a(5)*a(3))*idet
148 ainv(4) = (a(7)*a(6)-a(4)*a(9))*idet
149 ainv(5) = (a(1)*a(9)-a(7)*a(3))*idet
150 ainv(6) = (a(4)*a(3)-a(1)*a(6))*idet
151 ainv(7) = (a(4)*a(8)-a(7)*a(5))*idet
152 ainv(8) = (a(7)*a(2)-a(1)*a(8))*idet
153 ainv(9) = (a(1)*a(5)-a(4)*a(2))*idet
158 aug(i, j) = a((j-1)*nb + i)
166 if (abs(aug(i,k)) > abs(aug(p,k))) p = i
168 if (aug(p,k) == 0.0d0) then; info = 1; return;
end if
171 f = aug(k,j); aug(k,j) = aug(p,j); aug(p,j) = f
176 aug(k,j) = aug(k,j) / piv
181 if (f == 0.0d0) cycle
183 aug(i,j) = aug(i,j) - f*aug(k,j)
189 ainv((j-1)*nb + i) = aug(i, nb+j)
193 end subroutine block_inverse
198 type(hecmwst_saamg_blockdiag),
intent(in) :: d
199 real(kind=
kreal),
intent(in) :: x(:)
200 real(kind=
kreal),
intent(out) :: y(:)
201 integer(kind=kint) :: inode, base, ii, jj, off, nb
202 real(kind=
kreal) :: s
212 do inode = 1, d%nnode
214 off = (inode-1)*nb*nb
220 s = s + d%inv(off + (jj-1)*nb + ii) * x(base+jj)
237 type(hecmwst_saamg_blockdiag),
intent(in) :: d
238 type(hecmwst_saamg_bcsr),
intent(in) :: c
239 type(hecmwst_saamg_bcsr),
intent(out) :: dc
240 integer(kind=kint) :: nb, mb, inode, off, t, b0, ii, jj, cc, astat
241 real(kind=
kreal) :: s
244 if (c%nb /= nb .or. c%nbrow /= d%nnode)
then
245 write(*,*)
'hecmw_saamg_blockdiag_apply_bcsr: block-row mismatch', c%nb, nb, &
253 dc%n = c%n; dc%ncol = c%ncol; dc%nb = nb; dc%mb = mb
254 dc%nbrow = c%nbrow; dc%nbcol = c%nbcol; dc%nnzb = c%nnzb
255 allocate(dc%browptr(c%nbrow+1), dc%bcol(c%nnzb), dc%bval(nb*mb*c%nnzb), stat=astat)
257 dc%browptr = c%browptr; dc%bcol = c%bcol
260 do inode = 1, c%nbrow
261 off = (inode-1)*nb*nb
262 do t = c%browptr(inode), c%browptr(inode+1)-1
268 s = s + d%inv(off + (jj-1)*nb + ii) * c%bval(b0 + (cc-1)*nb + jj)
270 dc%bval(b0 + (cc-1)*nb + ii) = s
284 type(hecmwst_saamg_blockdiag),
intent(in) :: d
285 type(hecmwst_saamg_bcsr),
intent(inout) :: c
286 integer(kind=kint) :: nb, mb, inode, off, t, b0, ii, jj, cc
287 real(kind=
kreal) :: tmp(d%nb), s
289 if (c%nb /= nb .or. c%nbrow /= d%nnode)
then
290 write(*,*)
'hecmw_saamg_blockdiag_apply_bcsr_inplace: block-row mismatch', &
291 c%nb, nb, c%nbrow, d%nnode
295 do inode = 1, c%nbrow
296 off = (inode-1)*nb*nb
297 do t = c%browptr(inode), c%browptr(inode+1)-1
301 tmp(jj) = c%bval(b0 + (cc-1)*nb + jj)
306 s = s + d%inv(off + (jj-1)*nb + ii) * tmp(jj)
308 c%bval(b0 + (cc-1)*nb + ii) = s
319 type(hecmwst_saamg_blockdiag),
intent(in) :: d
320 real(kind=
kreal),
intent(in) :: x(:)
321 real(kind=
kreal),
intent(out) :: y(:)
322 integer(kind=kint) :: inode, base, ii, jj, off
323 real(kind=
kreal) :: s
326 do inode = 1, d%nnode
327 base = (inode-1)*d%nb
328 off = (inode-1)*d%nb*d%nb
332 s = s + d%dblk(off + (jj-1)*d%nb + ii) * x(base+jj)
342 type(hecmwst_saamg_blockdiag),
intent(inout) :: d
343 if (
allocated(d%dblk))
deallocate(d%dblk)
344 if (
allocated(d%inv))
deallocate(d%inv)
345 d%nnode = 0; d%nb = 0
358 real(kind=
kreal),
intent(in) :: diag(:), offd(:)
359 integer(kind=kint),
intent(in) :: m
360 real(kind=
kreal) :: lmax
361 real(kind=
kreal),
allocatable :: d(:), e(:)
362 integer(kind=kint) :: info
363 #ifdef HECMW_WITH_LAPACK
365 if (m <= 1) then; lmax = diag(1); return;
end if
366 allocate(d(m), e(m-1))
367 d(1:m) = diag(1:m); e(1:m-1) = offd(1:m-1)
368 call dsterf(m, d, e, info)
369 if (info == 0) then; lmax = d(m); else; lmax = maxval(diag(1:m));
end if
374 lmax = maxval(diag(1:m))
387 type(hecmwst_saamg_bcsr),
intent(in) :: a
388 type(hecmwst_saamg_blockdiag),
intent(in) :: d
389 integer(kind=kint),
intent(in) :: niter
390 real(kind=
kreal) :: lambda
391 real(kind=
kreal),
allocatable :: q(:), qp(:), w(:), aq(:), dv(:), alpha(:), beta(:)
392 real(kind=
kreal) :: qdq, wdw, bprev
393 integer(kind=kint) :: j, i, m
394 integer(kind=8) :: seed
396 allocate(q(a%n), qp(a%n), w(a%n), aq(a%n), dv(a%n), alpha(niter), beta(niter))
399 seed = 88172645463325252_8
401 seed = seed*6364136223846793005_8 + 1442695040888963407_8
402 q(i) = real(seed,
kreal)/9.223372036854776d18
406 if (qdq <= 0.0d0) then; lambda = 0.0d0;
deallocate(q,qp,w,aq,dv,alpha,beta); return;
end if
407 q = q / sqrt(qdq); qp = 0.0d0; bprev = 0.0d0; m = 0
412 alpha(j) = dot_product(aq, q)
413 w = w - alpha(j)*q - bprev*qp
416 if (wdw <= 0.0d0)
exit
419 qp = q; bprev = beta(j); q = w / beta(j)
423 deallocate(q, qp, w, aq, dv, alpha, beta)
434 real(kind=
kreal),
intent(in) :: lambda_hat
435 integer(kind=kint),
intent(in) :: deg
436 real(kind=
kreal),
intent(in) :: alpha
437 type(hecmwst_saamg_chebyshev),
intent(out) :: cheb
438 real(kind=
kreal) :: lmax, lmin
439 lmax = 1.1d0 * lambda_hat
442 cheb%theta = 0.5d0*(lmax + lmin)
443 cheb%delta = 0.5d0*(lmax - lmin)
444 cheb%sigma = cheb%theta / cheb%delta
451 type(hecmwst_saamg_bcsr),
intent(in) :: a
452 type(hecmwst_saamg_blockdiag),
intent(in) :: d
453 type(hecmwst_saamg_chebyshev),
intent(in) :: cheb
454 real(kind=
kreal),
intent(in) :: b(:)
455 real(kind=
kreal),
intent(inout) :: x(:)
456 logical,
intent(in) :: zero_init
457 real(kind=
kreal),
allocatable :: r(:), p(:), dr(:), ap(:)
458 real(kind=
kreal) :: rho, rho2, c1, c2
459 integer(kind=kint) :: it, n
462 allocate(r(n), p(n), dr(n), ap(n))
474 rho = 1.0d0 / cheb%sigma
480 rho2 = 1.0d0 / (2.0d0*cheb%sigma - rho)
483 c2 = 2.0d0 * rho2 / cheb%delta
488 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