20 public :: hecmwst_saamg_nodegraph
27 type hecmwst_saamg_nodegraph
28 integer(kind=kint) :: n = 0
29 integer(kind=kint),
allocatable :: index(:)
30 integer(kind=kint),
allocatable :: item(:)
31 end type hecmwst_saamg_nodegraph
44 type(hecmwst_saamg_bcsr),
intent(in) :: a
45 type(hecmwst_saamg_nodegraph),
intent(out) :: g
46 real(kind=
kreal),
optional,
intent(in) :: theta
47 integer(kind=kint) :: nb, nnode, inode, ii, k, jnode, deg, pos, t, nt
48 integer(kind=kint),
allocatable :: mark(:), touched(:)
49 real(kind=
kreal),
allocatable :: dnorm(:), acc(:)
50 real(kind=
kreal) :: th2
58 if (filt) filt = (theta > 0.0d0)
60 if (filt) th2 = theta*theta
62 allocate(g%index(nnode+1), mark(nnode), touched(nnode), acc(nnode), dnorm(nnode))
63 mark = 0; acc = 0.0d0; dnorm = 0.0d0
69 do k = a%browptr(inode), a%browptr(inode+1)-1
70 if (a%bcol(k) == inode)
then
72 dnorm(inode) = dnorm(inode) + a%bval((k-1)*nb*a%mb+ii)**2
77 dnorm(inode) = sqrt(dnorm(inode))
84 call gather_blocks(a, nb, inode, mark, touched, acc, nt)
90 else if (acc(jnode) >= th2 * dnorm(inode) * dnorm(jnode))
then
94 g%index(inode+1) = deg
97 g%index(inode+1) = g%index(inode+1) + g%index(inode)
99 allocate(g%item(g%index(nnode+1)))
104 call gather_blocks(a, nb, inode, mark, touched, acc, nt)
109 pos = pos + 1; g%item(pos) = jnode
110 else if (acc(jnode) >= th2 * dnorm(inode) * dnorm(jnode))
then
111 pos = pos + 1; g%item(pos) = jnode
115 deallocate(mark, touched, acc, dnorm)
122 subroutine gather_blocks(A, nb, inode, mark, touched, acc, nt)
123 type(hecmwst_saamg_bcsr),
intent(in) :: a
124 integer(kind=kint),
intent(in) :: nb, inode
125 integer(kind=kint),
intent(inout) :: mark(:), touched(:)
126 real(kind=
kreal),
intent(inout) :: acc(:)
127 integer(kind=kint),
intent(out) :: nt
128 integer(kind=kint) :: t, jnode, nrow, e, b0
129 real(kind=
kreal) :: bn
136 do t = a%browptr(inode), a%browptr(inode+1)-1
138 if (jnode == inode .or. jnode > nrow) cycle
139 b0 = (t-1)*nb*a%mb; bn = 0.0d0
141 bn = bn + a%bval(b0+e)*a%bval(b0+e)
143 mark(jnode) = inode; nt = nt + 1; touched(nt) = jnode; acc(jnode) = bn
145 end subroutine gather_blocks
149 type(hecmwst_saamg_nodegraph),
intent(inout) :: g
150 if (
allocated(g%index))
deallocate(g%index)
151 if (
allocated(g%item))
deallocate(g%item)
159 character(len=*),
intent(in) :: fname
160 real(kind=
kreal),
intent(in) :: coord(:)
161 integer(kind=kint),
intent(in) :: nnode
162 integer(kind=kint),
intent(in) :: aggr(:)
163 integer(kind=kint) :: iu, i
165 open(newunit=iu, file=fname, status=
'replace', action=
'write')
166 write(iu,
'(a)')
'# vtk DataFile Version 3.0'
167 write(iu,
'(a)')
'SA-AMG aggregates'
168 write(iu,
'(a)')
'ASCII'
169 write(iu,
'(a)')
'DATASET UNSTRUCTURED_GRID'
170 write(iu,
'(a,i0,a)')
'POINTS ', nnode,
' double'
172 write(iu,
'(es16.8,1x,es16.8,1x,es16.8)') &
173 coord(3*i-2), coord(3*i-1), coord(3*i)
175 write(iu,
'(a,i0,1x,i0)')
'CELLS ', nnode, 2*nnode
177 write(iu,
'(a,i0)')
'1 ', i-1
179 write(iu,
'(a,i0)')
'CELL_TYPES ', nnode
183 write(iu,
'(a,i0)')
'POINT_DATA ', nnode
184 write(iu,
'(a)')
'SCALARS agg_id int 1'
185 write(iu,
'(a)')
'LOOKUP_TABLE default'
187 write(iu,
'(i0)') aggr(i)
193 subroutine build_scan_order(g, omode, gid, order)
194 type(hecmwst_saamg_nodegraph),
intent(in) :: g
195 integer(kind=kint),
intent(in) :: omode
196 integer(kind=kint),
optional,
intent(in) :: gid(:)
197 integer(kind=kint),
intent(out) :: order(:)
198 integer(kind=kint),
allocatable :: key(:), visited(:), queue(:)
199 integer(kind=kint) :: n, i, k, pos, qh, qt, s
204 allocate(visited(n), queue(n)); visited = 0
207 if (visited(s) /= 0) cycle
208 qh = 1; qt = 1; queue(1) = s; visited(s) = 1
210 i = queue(qh); qh = qh + 1
211 pos = pos + 1; order(pos) = i
212 do k = g%index(i)+1, g%index(i+1)
213 if (visited(g%item(k)) == 0)
then
214 visited(g%item(k)) = 1; qt = qt + 1; queue(qt) = g%item(k)
219 deallocate(visited, queue)
224 if (
present(gid)) then; h = int(gid(i), 8); else; h = int(i, 8);
end if
225 h = ieor(h, ishft(h, 21)); h = ieor(h, ishft(h, -35)); h = ieor(h, ishft(h, 4))
226 h = h * 2685821657736338717_8
227 key(i) = int(iand(h, 2147483647_8), kind=
kint)
229 call sort_by_key(key, order, n)
234 key(i) = g%index(i+1) - g%index(i)
235 if (omode == 4) key(i) = -key(i)
237 call sort_by_key(key, order, n)
244 end subroutine build_scan_order
247 subroutine sort_by_key(key, order, n)
248 integer(kind=kint),
intent(in) :: key(:)
249 integer(kind=kint),
intent(out) :: order(:)
250 integer(kind=kint),
intent(in) :: n
251 integer(kind=kint),
allocatable :: work(:), kwork(:), karr(:)
252 integer(kind=kint) :: i
253 allocate(work(n), kwork(n), karr(n))
258 call msort(karr, order, kwork, work, 1, n)
259 deallocate(work, kwork, karr)
261 recursive subroutine msort(k, idx, kw, iw, lo, hi)
262 integer(kind=kint),
intent(inout) :: k(:), idx(:), kw(:), iw(:)
263 integer(kind=kint),
intent(in) :: lo, hi
264 integer(kind=kint) :: mid, a, b, c
265 if (hi - lo < 1)
return
267 call msort(k, idx, kw, iw, lo, mid)
268 call msort(k, idx, kw, iw, mid+1, hi)
269 a = lo; b = mid + 1; c = lo
270 do while (a <= mid .and. b <= hi)
271 if (k(a) <= k(b))
then
272 kw(c) = k(a); iw(c) = idx(a); a = a + 1
274 kw(c) = k(b); iw(c) = idx(b); b = b + 1
278 do while (a <= mid); kw(c) = k(a); iw(c) = idx(a); a = a + 1; c = c + 1;
end do
279 do while (b <= hi); kw(c) = k(b); iw(c) = idx(b); b = b + 1; c = c + 1;
end do
280 k(lo:hi) = kw(lo:hi); idx(lo:hi) = iw(lo:hi)
282 end subroutine sort_by_key
297 type(hecmwst_saamg_nodegraph),
intent(in) :: g
298 integer(kind=kint),
intent(in) :: min_size, max_size
299 integer(kind=kint),
allocatable,
intent(out) :: aggr(:)
300 integer(kind=kint),
intent(out) :: naggr
301 integer(kind=kint),
optional,
intent(in) :: order_mode
302 integer(kind=kint),
optional,
intent(in) :: gid(:)
303 integer(kind=kint),
allocatable :: state(:), state1(:), sz(:), order(:)
304 integer(kind=kint) :: n, i, k, csz, ii, omode
307 allocate(state(n), state1(n), sz(n))
312 if (g%index(i+1) == g%index(i)) state(i) = -1
316 if (
present(order_mode)) omode = order_mode
318 call build_scan_order(g, omode, gid, order)
333 if (state(i) /= 0) cycle
334 if (.not. all_neighbors_free(g, state, i)) cycle
338 do k = g%index(i)+1, g%index(i+1)
339 if (csz >= max_size)
exit
340 state(g%item(k)) = naggr
349 if (state(i) > 0) sz(state(i)) = sz(state(i)) + 1
353 call phase2_attach(g, state, state1, sz, max_size)
356 call phase3_components(g, state, sz, naggr, max_size)
359 call merge_small(g, state, sz, naggr, min_size)
362 call compact_ids(state, n, naggr)
366 if (state(i) < 0)
then
373 deallocate(state, state1, sz)
380 logical function all_neighbors_free(g, state, i)
result(ok)
381 type(hecmwst_saamg_nodegraph),
intent(in) :: g
382 integer(kind=kint),
intent(in) :: state(:), i
383 integer(kind=kint) :: k
385 do k = g%index(i)+1, g%index(i+1)
386 if (state(g%item(k)) /= 0)
then
390 end function all_neighbors_free
394 subroutine phase2_attach(g, state, state1, sz, max_size)
395 type(hecmwst_saamg_nodegraph),
intent(in) :: g
396 integer(kind=kint),
intent(inout) :: state(:), sz(:)
397 integer(kind=kint),
intent(in) :: state1(:), max_size
398 integer(kind=kint),
allocatable :: str(:), touched(:)
399 integer(kind=kint) :: n, i, k, a, nt, t, best, beststr
401 allocate(str(n), touched(n)); str = 0
403 if (state(i) /= 0) cycle
405 do k = g%index(i)+1, g%index(i+1)
406 a = state1(g%item(k))
408 if (str(a) == 0) then; nt = nt + 1; touched(nt) = a;
end if
412 best = 0; beststr = 0
415 if (sz(a) < max_size .and. str(a) > beststr)
then
416 beststr = str(a); best = a
420 state(i) = best; sz(best) = sz(best) + 1
426 deallocate(str, touched)
427 end subroutine phase2_attach
433 subroutine phase3_components(g, state, sz, naggr, max_size)
434 type(hecmwst_saamg_nodegraph),
intent(in) :: g
435 integer(kind=kint),
intent(inout) :: state(:), sz(:), naggr
436 integer(kind=kint),
intent(in) :: max_size
437 integer(kind=kint),
allocatable :: queue(:)
438 integer(kind=kint) :: n, i, head, tail, u, k, v, cnt
442 if (state(i) /= 0) cycle
444 head = 1; tail = 1; queue(1) = i; state(i) = naggr; cnt = 1
445 do while (head <= tail .and. cnt < max_size)
446 u = queue(head); head = head + 1
447 do k = g%index(u)+1, g%index(u+1)
449 if (state(v) == 0)
then
450 state(v) = naggr; cnt = cnt + 1
451 tail = tail + 1; queue(tail) = v
452 if (cnt >= max_size)
exit
459 end subroutine phase3_components
464 subroutine merge_small(g, state, sz, naggr, min_size)
465 type(hecmwst_saamg_nodegraph),
intent(in) :: g
466 integer(kind=kint),
intent(inout) :: state(:), sz(:)
467 integer(kind=kint),
intent(in) :: naggr, min_size
468 integer(kind=kint),
allocatable :: str(:), touched(:), stuck(:)
469 integer(kind=kint) :: n, i, k, a, b, small, nt, t, best, beststr
471 allocate(str(naggr), touched(naggr), stuck(naggr))
478 if (sz(a) > 0 .and. sz(a) < min_size .and. stuck(a) == 0)
then
487 if (state(i) /= small) cycle
488 do k = g%index(i)+1, g%index(i+1)
490 if (b > 0 .and. b /= small)
then
491 if (str(b) == 0) then; nt = nt + 1; touched(nt) = b;
end if
496 best = 0; beststr = 0
499 if (str(b) > beststr) then; beststr = str(b); best = b;
end if
505 write(*,
'(a,i0,a)')
'hecmw_saamg merge_small: aggregate ', small, &
506 ' has no neighbor aggregate; left below min_size'
511 if (state(i) == small) state(i) = best
513 sz(best) = sz(best) + sz(small)
517 deallocate(str, touched, stuck)
518 end subroutine merge_small
521 subroutine compact_ids(state, n, naggr)
522 integer(kind=kint),
intent(inout) :: state(:), naggr
523 integer(kind=kint),
intent(in) :: n
524 integer(kind=kint),
allocatable :: map(:)
525 integer(kind=kint) :: i, a, cnt
526 allocate(map(naggr)); map = 0
531 if (map(a) == 0) then; cnt = cnt + 1; map(a) = cnt;
end if
537 end subroutine compact_ids
Smoothed Aggregation AMG preconditioner : node graph + aggregation.
subroutine, public hecmw_saamg_aggregate(g, min_size, max_size, aggr, naggr, order_mode, gid)
Vanek 3-phase aggregation + min-size forced merge. aggr(1:n): 1..naggr for aggregated nodes,...
subroutine, public hecmw_saamg_nodegraph_free(g)
subroutine, public hecmw_saamg_build_nodegraph(A, g, theta)
Build the node graph from the block-CSR operator A. With theta (optional) > 0, apply a strength-of-co...
subroutine, public hecmw_saamg_write_vtk(fname, coord, nnode, aggr)
Write a legacy-VTK point cloud colored by aggregate id (ParaView diagnostic). coord is (x,...
Smoothed Aggregation AMG preconditioner : internal block-CSR matrix.
Smoothed Aggregation AMG preconditioner : kind parameters.
integer(kind=4), parameter kreal
integer(kind=4), parameter kint