FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
hecmw_mf_dist.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2026 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
9  use hecmw_util
10  use m_hecmw_comm_f
12  implicit none
13 
14  private
15  public :: hecmwst_mf_map
16  public :: hecmw_mf_dist_map_build
18  public :: hecmw_mf_dist_rowtiles
19  public :: hecmw_mf_dist_fsgrid
20  public :: hecmw_mf_dist_fsrank
22  public :: hecmwst_mf_gmat
23  public :: hecmw_mf_dist_gmat_build
24  public :: hecmw_mf_dist_gmat_part
25  public :: hecmw_mf_dist_gmat_vals
27  public :: hecmw_mf_dist_gmat_words
29  public :: hecmw_mf_dist_gather_vec
30 
37  type hecmwst_mf_map
38  integer(kind=kint) :: nprocs = 1
39  integer(kind=kint) :: myrank = 0
40  integer(kind=kint) :: comm = 0
41  integer(kind=kint) :: nupper = 0
42  integer(kind=kint), allocatable :: owner(:)
43  logical, allocatable :: upper(:)
44  integer(kind=kint), allocatable :: uplist(:)
45  integer(kind=kint), allocatable :: rbeg(:)
46  integer(kind=kint), allocatable :: rcnt(:)
47  end type hecmwst_mf_map
48 
59  type hecmwst_mf_gmat
60  type(hecmwST_matrix) :: mat
61  integer(kind=kint) :: nblk = 0
62  integer(kind=kint), allocatable :: nn(:)
63  integer(kind=kint), allocatable :: ndisp(:)
64  integer(kind=kint), allocatable :: vblk(:)
65  integer(kind=kint), allocatable :: stream(:)
66  integer(kind=kint), allocatable :: xptr(:)
67  integer(kind=kint), allocatable :: xcol(:)
68  integer(kind=kint), allocatable :: gid(:)
69  integer(kind=kint), allocatable :: g2s(:)
70  integer(kind=kint), allocatable :: scnt(:)
71  integer(kind=kint), allocatable :: ssel(:)
72  integer(kind=kint), allocatable :: rcnt(:)
73  integer(kind=kint), allocatable :: rdst(:)
74  end type hecmwst_mf_gmat
75 
79  real(kind=kreal), parameter :: mf_map_promote = 1.2d0
80 
85  real(kind=kreal), parameter :: mf_map_promote_heavy = 0.5d0
86  integer(kind=8), parameter :: MF_MAP_PROMOTE_ABS = 500000000000_8
87 
90  integer(kind=8), parameter :: MF_MAP_WPF = 2500_8
91 
95  integer(kind=kint), parameter :: MF_2D_FSTPR = 8
96 
97 contains
98 
107  subroutine hecmw_mf_dist_map_build(sym, map)
108  implicit none
109  type(hecmwst_mf_symbolic), intent(in) :: sym
110  type(hecmwst_mf_map), intent(out) :: map
111  integer(kind=8), allocatable :: wt(:)
112  integer(kind=kint), allocatable :: cptr(:), clist(:), wptr(:)
113  integer(kind=kint) :: ns, s, p, c, i, nroot, nup, cbest
114  integer(kind=8) :: w, wbest, b
115 
116  ns = sym%nsuper
117  map%nprocs = hecmw_comm_get_size()
118  map%myrank = hecmw_comm_get_rank()
119  map%comm = hecmw_comm_get_comm()
120  allocate(map%owner(ns), map%upper(ns))
121 
122  ! subtree weights: the factorization flops estimate of the supernode (the formula of
123  ! mf_estimate) plus the factor panel words scaled by MF_MAP_WPF, accumulated bottom-up
124  ! (the ascending numbering places children before parents); the words term charges the
125  ! memory-bound assembly and store work of the many small fronts, which the flops alone
126  ! underrate
127  allocate(wt(ns))
128  do s = 1, ns
129  w = 0
130  do i = sym%rptr(s), sym%rptr(s+1) - 1
131  w = w + sym%ndof(sym%rlist(i))
132  enddo
133  b = w - sym_cdofcount(s)
134  wt(s) = (w*(w+1)*(2*w+1) - b*(b+1)*(2*b+1))/6 + mf_map_wpf*w*sym_cdofcount(s)
135  enddo
136  do s = 1, ns
137  p = sym%sparent(s)
138  if (p /= 0) wt(p) = wt(p) + wt(s)
139  enddo
140 
141  ! children in ascending order
142  allocate(cptr(ns+1), clist(max(ns, 1)), wptr(ns))
143  cptr(1:ns+1) = 0
144  do s = 1, ns
145  p = sym%sparent(s)
146  if (p /= 0) cptr(p+1) = cptr(p+1) + 1
147  enddo
148  cptr(1) = 1
149  do s = 1, ns
150  cptr(s+1) = cptr(s) + cptr(s+1)
151  enddo
152  wptr(1:ns) = cptr(1:ns)
153  do s = 1, ns
154  p = sym%sparent(s)
155  if (p /= 0) then
156  clist(wptr(p)) = s
157  wptr(p) = wptr(p) + 1
158  endif
159  enddo
160 
161  ! rank ranges: the roots share all ranks, an upper front promotes and packs the
162  ! subtrees below it within its range; parents carry larger indices, so a descending
163  ! sweep sets every range before it is read, and a front promoted higher up finds its
164  ! children already assigned
165  allocate(map%rbeg(ns), map%rcnt(ns))
166  map%rcnt(1:ns) = -1
167  nroot = 0
168  do s = 1, ns
169  if (sym%sparent(s) == 0) nroot = nroot + 1
170  enddo
171  i = 0
172  do s = 1, ns
173  if (sym%sparent(s) == 0) then
174  i = i + 1
175  wptr(i) = s
176  endif
177  enddo
178  call mf_map_split(wt, wptr(1:nroot), 0, map%nprocs, map%rbeg, map%rcnt)
179  do s = ns, 1, -1
180  if (map%rcnt(s) < 0) then
181  p = sym%sparent(s)
182  map%rbeg(s) = map%rbeg(p)
183  map%rcnt(s) = 1
184  endif
185  if (map%rcnt(s) > 1) call mf_map_pack(s)
186  enddo
187 
188  ! owners bottom-up: a single-rank supernode is owned by its rank, an upper front by the
189  ! owner of its heaviest child subtree (smallest child index on ties)
190  nup = 0
191  do s = 1, ns
192  if (map%rcnt(s) <= 1) then
193  map%owner(s) = map%rbeg(s)
194  map%upper(s) = .false.
195  else
196  cbest = 0
197  wbest = -1
198  do i = cptr(s), cptr(s+1) - 1
199  c = clist(i)
200  if (wt(c) > wbest) then
201  wbest = wt(c)
202  cbest = c
203  endif
204  enddo
205  if (cbest > 0) then
206  map%owner(s) = map%owner(cbest)
207  else
208  map%owner(s) = map%rbeg(s)
209  endif
210  map%upper(s) = .true.
211  nup = nup + 1
212  endif
213  enddo
214  map%nupper = nup
215  allocate(map%uplist(max(nup, 1)))
216  nup = 0
217  do s = 1, ns
218  if (map%upper(s)) then
219  nup = nup + 1
220  map%uplist(nup) = s
221  endif
222  enddo
223  deallocate(wt, cptr, clist, wptr)
224 
225  contains
226 
228  function sym_cdofcount(s0) result(nc)
229  integer(kind=kint), intent(in) :: s0
230  integer(kind=kint) :: nc, k
231  nc = 0
232  do k = sym%sptr(s0), sym%sptr(s0+1) - 1
233  nc = nc + sym%ndof(k)
234  enddo
235  end function sym_cdofcount
236 
245  subroutine mf_map_pack(s0)
246  integer(kind=kint), intent(in) :: s0
247  integer(kind=kint), allocatable :: pool(:)
248  integer(kind=8), allocatable :: load(:)
249  integer(kind=kint) :: npool, i0, j0, c0, r0, nr0, rmin
250  integer(kind=8) :: tot
251  real(kind=kreal) :: th
252  logical :: grew
253 
254  r0 = map%rbeg(s0)
255  nr0 = map%rcnt(s0)
256  allocate(pool(ns), load(0:nr0-1))
257  npool = 0
258  tot = 0
259  do i0 = cptr(s0), cptr(s0+1) - 1
260  c0 = clist(i0)
261  if (map%rcnt(c0) < 0) then
262  npool = npool + 1
263  pool(npool) = c0
264  tot = tot + wt(c0)
265  endif
266  enddo
267  grew = .true.
268  do while (grew)
269  grew = .false.
270  i0 = 1
271  do while (i0 <= npool)
272  c0 = pool(i0)
273  th = mf_map_promote
274  if (wt(c0) >= mf_map_promote_abs) th = mf_map_promote_heavy
275  if (real(wt(c0), kind=kreal)*nr0 > th*real(tot, kind=kreal)) then
276  map%rbeg(c0) = r0
277  map%rcnt(c0) = nr0
278  tot = tot - wt(c0)
279  pool(i0) = pool(npool)
280  npool = npool - 1
281  do j0 = cptr(c0), cptr(c0+1) - 1
282  npool = npool + 1
283  pool(npool) = clist(j0)
284  tot = tot + wt(clist(j0))
285  enddo
286  grew = .true.
287  else
288  i0 = i0 + 1
289  endif
290  enddo
291  enddo
292  call mf_sort_lpt(pool, npool)
293  load(0:nr0-1) = 0
294  do i0 = 1, npool
295  rmin = 0
296  do j0 = 1, nr0 - 1
297  if (load(j0) < load(rmin)) rmin = j0
298  enddo
299  c0 = pool(i0)
300  map%rbeg(c0) = r0 + rmin
301  map%rcnt(c0) = 1
302  ! a zero weight still loads its rank one unit, so tiny subtrees spread out
303  load(rmin) = load(rmin) + max(wt(c0), 1_8)
304  enddo
305  deallocate(pool, load)
306  end subroutine mf_map_pack
307 
310  subroutine mf_sort_lpt(list, n0)
311  integer(kind=kint), intent(inout) :: list(:)
312  integer(kind=kint), intent(in) :: n0
313  integer(kind=kint) :: i0, j0, k0, t0
314 
315  do i0 = n0/2, 1, -1
316  j0 = i0
317  do
318  k0 = 2*j0
319  if (k0 > n0) exit
320  if (k0 < n0) then
321  if (lpt_after(list(k0+1), list(k0))) k0 = k0 + 1
322  endif
323  if (.not. lpt_after(list(k0), list(j0))) exit
324  t0 = list(j0)
325  list(j0) = list(k0)
326  list(k0) = t0
327  j0 = k0
328  enddo
329  enddo
330  do i0 = n0, 2, -1
331  t0 = list(1)
332  list(1) = list(i0)
333  list(i0) = t0
334  j0 = 1
335  do
336  k0 = 2*j0
337  if (k0 > i0 - 1) exit
338  if (k0 < i0 - 1) then
339  if (lpt_after(list(k0+1), list(k0))) k0 = k0 + 1
340  endif
341  if (.not. lpt_after(list(k0), list(j0))) exit
342  t0 = list(j0)
343  list(j0) = list(k0)
344  list(k0) = t0
345  j0 = k0
346  enddo
347  enddo
348  end subroutine mf_sort_lpt
349 
351  logical function lpt_after(a0, b0)
352  integer(kind=kint), intent(in) :: a0, b0
353  lpt_after = (wt(a0) < wt(b0)) .or. (wt(a0) == wt(b0) .and. a0 > b0)
354  end function lpt_after
355 
356  end subroutine hecmw_mf_dist_map_build
357 
361  subroutine mf_map_split(wt, list, r0, np, rbeg, rcnt)
362  implicit none
363  integer(kind=8), intent(in) :: wt(:)
364  integer(kind=kint), intent(in) :: list(:)
365  integer(kind=kint), intent(in) :: r0, np
366  integer(kind=kint), intent(inout) :: rbeg(:), rcnt(:)
367  integer(kind=8) :: ctot, c
368  integer(kind=kint) :: i, s, b0, b1
369 
370  ctot = 0
371  do i = 1, size(list)
372  ctot = ctot + wt(list(i))
373  enddo
374  c = 0
375  do i = 1, size(list)
376  s = list(i)
377  if (ctot > 0) then
378  ! rounded boundaries: a floor would push both halves of an even split onto the
379  ! first rank whenever the cut misses an integer
380  b0 = int((2_8*np*c + ctot)/(2_8*ctot), kind=kint)
381  c = c + wt(s)
382  b1 = int((2_8*np*c + ctot)/(2_8*ctot), kind=kint)
383  else
384  b0 = 0
385  b1 = 0
386  endif
387  if (b0 > np - 1) b0 = np - 1
388  if (b1 <= b0) b1 = b0 + 1
389  rbeg(s) = r0 + b0
390  rcnt(s) = min(b1, np) - b0
391  enddo
392  end subroutine mf_map_split
393 
395  implicit none
396  type(hecmwst_mf_map), intent(inout) :: map
397 
398  map%nprocs = 1
399  map%nupper = 0
400  if (allocated(map%owner)) deallocate(map%owner)
401  if (allocated(map%upper)) deallocate(map%upper)
402  if (allocated(map%uplist)) deallocate(map%uplist)
403  if (allocated(map%rbeg)) deallocate(map%rbeg)
404  if (allocated(map%rcnt)) deallocate(map%rcnt)
405  end subroutine hecmw_mf_dist_map_finalize
406 
415  subroutine hecmw_mf_dist_rowtiles(sym, map, tile, s, ndel, ncbt, ctb, towner)
416  implicit none
417  type(hecmwst_mf_symbolic), intent(in) :: sym
418  type(hecmwst_mf_map), intent(in) :: map
419  integer(kind=kint), intent(in) :: tile, s, ndel
420  integer(kind=kint), intent(out) :: ncbt
421  integer(kind=kint), allocatable, intent(inout) :: ctb(:)
422  integer(kind=kint), allocatable, intent(inout) :: towner(:)
423  integer(kind=kint) :: nown, nrow_nodes, ncol, i, k, nd, rel, cur, nr, t, b
424  integer(kind=8) :: ctot, c, w
425 
426  nown = sym%sptr(s+1) - sym%sptr(s)
427  nrow_nodes = sym%rptr(s+1) - sym%rptr(s)
428  ncol = ndel
429  do k = sym%sptr(s), sym%sptr(s+1) - 1
430  ncol = ncol + sym%ndof(k)
431  enddo
432  if (allocated(ctb)) then
433  if (size(ctb) < nrow_nodes - nown + 1) deallocate(ctb, towner)
434  endif
435  if (.not. allocated(ctb)) allocate(ctb(0:max(nrow_nodes - nown, 1)), towner(max(nrow_nodes - nown, 1)))
436  ncbt = 0
437  ctb(0) = 0
438  rel = 0
439  cur = 0
440  do i = nown + 1, nrow_nodes
441  nd = sym%ndof(sym%rlist(sym%rptr(s)+i-1))
442  if (rel > cur .and. rel + nd - cur > tile) then
443  ncbt = ncbt + 1
444  ctb(ncbt) = rel
445  cur = rel
446  endif
447  rel = rel + nd
448  enddo
449  if (rel > cur .or. ncbt == 0) then
450  if (rel > 0) then
451  ncbt = ncbt + 1
452  ctb(ncbt) = rel
453  endif
454  endif
455  if (ncbt == 0) return
456 
457  nr = map%rcnt(s)
458  ctot = 0
459  do t = 1, ncbt
460  ctot = ctot + int(ctb(t) - ctb(t-1), 8)*(ncol + ctb(t))
461  enddo
462  c = 0
463  do t = 1, ncbt
464  w = int(ctb(t) - ctb(t-1), 8)*(ncol + ctb(t))
465  b = int(((2_8*c + w)*nr)/(2_8*ctot), kind=kint)
466  if (b > nr - 1) b = nr - 1
467  towner(t) = map%rbeg(s) + b
468  c = c + w
469  enddo
470  end subroutine hecmw_mf_dist_rowtiles
471 
477  subroutine hecmw_mf_dist_fsgrid(map, s, ntc, pr, pc)
478  implicit none
479  type(hecmwst_mf_map), intent(in) :: map
480  integer(kind=kint), intent(in) :: s, ntc
481  integer(kind=kint), intent(out) :: pr, pc
482  integer(kind=kint) :: ng
483 
484  ng = (ntc*(ntc+1)/2) / mf_2d_fstpr
485  if (ng > map%rcnt(s)) ng = map%rcnt(s)
486  if (ng < 1) ng = 1
487  pc = 1
488  do while ((pc+1)*(pc+1) <= ng)
489  pc = pc + 1
490  enddo
491  pr = ng / pc
492  end subroutine hecmw_mf_dist_fsgrid
493 
497  function hecmw_mf_dist_fsrank(map, s, pr, pc, i, j) result(r)
498  implicit none
499  type(hecmwst_mf_map), intent(in) :: map
500  integer(kind=kint), intent(in) :: s, pr, pc, i, j
501  integer(kind=kint) :: r, gp
502 
503  gp = mod(i-1, pr)*pc + mod(j-1, pc)
504  if (gp == 0) then
505  r = map%owner(s)
506  else
507  r = map%rbeg(s) + gp - 1
508  if (r >= map%owner(s)) r = r + 1
509  endif
510  end function hecmw_mf_dist_fsrank
511 
514  subroutine hecmw_mf_dist_symbolic_bcast(sym, root)
515  implicit none
516  type(hecmwst_mf_symbolic), intent(inout) :: sym
517  integer(kind=kint), intent(in) :: root
518  integer(kind=kint) :: hdr(6)
519  integer(kind=kint) :: n, ns, nrl, ncm, comm
520 
521  if (hecmw_comm_get_size() == 1) return
522  comm = hecmw_comm_get_comm()
523  if (hecmw_comm_get_rank() == root) then
524  hdr(1) = sym%nnode
525  hdr(2) = sym%nsuper
526  hdr(3) = sym%nmerge
527  hdr(4) = sym%max_front
528  hdr(5) = sym%rptr(sym%nsuper+1) - 1
529  hdr(6) = sym%cmap_ptr(sym%nsuper+1) - 1
530  endif
531  call hecmw_bcast_i_comm(hdr, 6, root, comm)
532  n = hdr(1)
533  ns = hdr(2)
534  nrl = hdr(5)
535  ncm = hdr(6)
536  if (hecmw_comm_get_rank() /= root) then
538  sym%nnode = n
539  sym%nsuper = ns
540  sym%nmerge = hdr(3)
541  sym%max_front = hdr(4)
542  allocate(sym%perm(n), sym%invp(n), sym%ndof(n), sym%parent(n), sym%colcnt(n))
543  allocate(sym%sptr(ns+1), sym%sparent(ns), sym%rptr(ns+1), sym%rlist(nrl))
544  allocate(sym%cmap_ptr(ns+1), sym%cmap(max(ncm, 1)))
545  endif
546  call hecmw_bcast_i_comm(sym%perm, n, root, comm)
547  call hecmw_bcast_i_comm(sym%invp, n, root, comm)
548  call hecmw_bcast_i_comm(sym%ndof, n, root, comm)
549  call hecmw_bcast_i_comm(sym%parent, n, root, comm)
550  call hecmw_bcast_i_comm(sym%colcnt, n, root, comm)
551  call hecmw_bcast_i_comm(sym%sptr, ns + 1, root, comm)
552  call hecmw_bcast_i_comm(sym%sparent, ns, root, comm)
553  call hecmw_bcast_i_comm(sym%rptr, ns + 1, root, comm)
554  call hecmw_bcast_i_comm(sym%rlist, nrl, root, comm)
555  call hecmw_bcast_i_comm(sym%cmap_ptr, ns + 1, root, comm)
556  if (ncm > 0) call hecmw_bcast_i_comm(sym%cmap, ncm, root, comm)
557  end subroutine hecmw_mf_dist_symbolic_bcast
558 
564  subroutine hecmw_mf_dist_gmat_build(hecMESH, hecMAT, gmat)
565  implicit none
566  type(hecmwst_local_mesh), intent(in) :: hecmesh
567  type(hecmwst_matrix), intent(in) :: hecmat
568  type(hecmwst_mf_gmat), intent(inout) :: gmat
569  integer(kind=kint), allocatable :: ibuf(:), ilen(:), idisp(:), gc(:), sidx(:), itmp(:)
570  integer(kind=kint) :: np, me, comm, nd, n, ng, i, j, k, l, m, r, ptr, ncols, grow, maxcols
571  integer(kind=kint) :: nl, nu, g
572 
573  np = hecmw_comm_get_size()
574  me = hecmw_comm_get_rank()
575  comm = hecmw_comm_get_comm()
576  nd = hecmat%NDOF
577  n = hecmat%N
578  call hecmw_mf_dist_gmat_finalize(gmat)
579  allocate(gmat%nn(np), gmat%ndisp(np+1), gmat%vblk(np), ilen(np), idisp(np))
580  call hecmw_allgather_int_1(n, gmat%nn, comm)
581  gmat%ndisp(1) = 0
582  do r = 1, np
583  gmat%ndisp(r+1) = gmat%ndisp(r) + gmat%nn(r)
584  enddo
585  ng = gmat%ndisp(np+1)
586  allocate(gmat%gid(ng))
587  call hecmw_allgatherv_int(hecmesh%global_node_ID, n, gmat%gid, gmat%nn, gmat%ndisp, comm)
588  ! the global rows are numbered by ascending user node id, not by rank concatenation,
589  ! so the ordering input does not depend on the process count or the partitioning
590  allocate(gmat%g2s(ng), sidx(ng), itmp(ng))
591  do i = 1, ng
592  sidx(i) = i
593  enddo
594  call sort_by_gid(sidx, ng)
595  do k = 1, ng
596  gmat%g2s(sidx(k)) = k
597  itmp(k) = gmat%gid(sidx(k))
598  enddo
599  gmat%gid(1:ng) = itmp(1:ng)
600  deallocate(sidx, itmp)
601 
602  ! the int stream: per internal row its column count and the global column ids
603  m = n + (hecmat%indexL(n) - hecmat%indexL(0)) + (hecmat%indexU(n) - hecmat%indexU(0))
604  allocate(ibuf(max(m, 1)))
605  ptr = 0
606  do i = 1, n
607  ptr = ptr + 1
608  ibuf(ptr) = (hecmat%indexL(i) - hecmat%indexL(i-1)) + (hecmat%indexU(i) - hecmat%indexU(i-1))
609  do k = hecmat%indexL(i-1)+1, hecmat%indexL(i)
610  ptr = ptr + 1
611  ibuf(ptr) = mf_global_node(hecmesh, gmat, me, hecmat%itemL(k))
612  enddo
613  do k = hecmat%indexU(i-1)+1, hecmat%indexU(i)
614  ptr = ptr + 1
615  ibuf(ptr) = mf_global_node(hecmesh, gmat, me, hecmat%itemU(k))
616  enddo
617  enddo
618  call hecmw_allgather_int_1(m, ilen, comm)
619  idisp(1) = 0
620  do r = 2, np
621  idisp(r) = idisp(r-1) + ilen(r-1)
622  enddo
623  allocate(gmat%stream(idisp(np) + ilen(np)))
624  call hecmw_allgatherv_int(ibuf, m, gmat%stream, ilen, idisp, comm)
625  deallocate(ibuf)
626  ! per row one diagonal block plus the neighbor blocks, so the block count of a rank
627  ! equals its int stream length
628  gmat%vblk(1:np) = ilen(1:np)
629  gmat%nblk = idisp(np) + ilen(np)
630  ! translate the stream columns into the gid numbering (the row segments keep the
631  ! gathered order; the row id of the k-th segment is g2s(k))
632  ptr = 0
633  do i = 1, ng
634  ncols = gmat%stream(ptr+1)
635  do j = 1, ncols
636  gmat%stream(ptr+1+j) = gmat%g2s(gmat%stream(ptr+1+j))
637  enddo
638  ptr = ptr + 1 + ncols
639  enddo
640  call mf_gmat_closure(gmat, ng)
641  gmat%mat%N = ng
642  gmat%mat%NP = ng
643  gmat%mat%NDOF = nd
644  nullify(gmat%mat%indexL, gmat%mat%indexU, gmat%mat%itemL, gmat%mat%itemU)
645  nullify(gmat%mat%D, gmat%mat%AL, gmat%mat%AU)
646  nullify(gmat%mat%B, gmat%mat%X, gmat%mat%A, gmat%mat%indexA, gmat%mat%itemA)
647  deallocate(ilen, idisp)
648  if (me /= 0) return
649 
650  ! the full profile of rank 0: count the lower/upper split per global row, then sort
651  ! the columns of a row ascending
652  allocate(gmat%mat%indexL(0:ng), gmat%mat%indexU(0:ng))
653  gmat%mat%indexL(0:ng) = 0
654  gmat%mat%indexU(0:ng) = 0
655  maxcols = 0
656  ptr = 0
657  do r = 1, np
658  do i = 1, gmat%nn(r)
659  grow = gmat%g2s(gmat%ndisp(r) + i)
660  ncols = gmat%stream(ptr+1)
661  maxcols = max(maxcols, ncols + gmat%xptr(grow) - gmat%xptr(grow-1))
662  do j = 1, ncols
663  g = gmat%stream(ptr+1+j)
664  if (g < grow) then
665  gmat%mat%indexL(grow) = gmat%mat%indexL(grow) + 1
666  else
667  gmat%mat%indexU(grow) = gmat%mat%indexU(grow) + 1
668  endif
669  enddo
670  do k = gmat%xptr(grow-1)+1, gmat%xptr(grow)
671  if (gmat%xcol(k) < grow) then
672  gmat%mat%indexL(grow) = gmat%mat%indexL(grow) + 1
673  else
674  gmat%mat%indexU(grow) = gmat%mat%indexU(grow) + 1
675  endif
676  enddo
677  ptr = ptr + 1 + ncols
678  enddo
679  enddo
680  do i = 1, ng
681  gmat%mat%indexL(i) = gmat%mat%indexL(i-1) + gmat%mat%indexL(i)
682  gmat%mat%indexU(i) = gmat%mat%indexU(i-1) + gmat%mat%indexU(i)
683  enddo
684  gmat%mat%NPL = gmat%mat%indexL(ng)
685  gmat%mat%NPU = gmat%mat%indexU(ng)
686  allocate(gmat%mat%itemL(max(gmat%mat%NPL, 1)), gmat%mat%itemU(max(gmat%mat%NPU, 1)))
687  allocate(gc(max(maxcols, 1)))
688  ptr = 0
689  do r = 1, np
690  do i = 1, gmat%nn(r)
691  grow = gmat%g2s(gmat%ndisp(r) + i)
692  ncols = gmat%stream(ptr+1)
693  do j = 1, ncols
694  gc(j) = gmat%stream(ptr+1+j)
695  enddo
696  ptr = ptr + 1 + ncols
697  do k = gmat%xptr(grow-1)+1, gmat%xptr(grow)
698  ncols = ncols + 1
699  gc(ncols) = gmat%xcol(k)
700  enddo
701  ! insertion sort by the global column id (unique within a row)
702  do j = 2, ncols
703  g = gc(j)
704  l = j - 1
705  do while (l >= 1)
706  if (gc(l) <= g) exit
707  gc(l+1) = gc(l)
708  l = l - 1
709  enddo
710  gc(l+1) = g
711  enddo
712  nl = 0
713  nu = 0
714  do j = 1, ncols
715  if (gc(j) < grow) then
716  nl = nl + 1
717  gmat%mat%itemL(gmat%mat%indexL(grow-1) + nl) = gc(j)
718  else
719  nu = nu + 1
720  gmat%mat%itemU(gmat%mat%indexU(grow-1) + nu) = gc(j)
721  endif
722  enddo
723  enddo
724  enddo
725  deallocate(gc)
726 
727  contains
728 
730  subroutine sort_by_gid(idx, n0)
731  integer(kind=kint), intent(inout) :: idx(:)
732  integer(kind=kint), intent(in) :: n0
733  integer(kind=kint) :: i0, t0
734  do i0 = n0/2, 1, -1
735  call sift_by_gid(idx, i0, n0)
736  enddo
737  do i0 = n0, 2, -1
738  t0 = idx(1)
739  idx(1) = idx(i0)
740  idx(i0) = t0
741  call sift_by_gid(idx, 1, i0-1)
742  enddo
743  end subroutine sort_by_gid
744 
745  subroutine sift_by_gid(idx, s0, e0)
746  integer(kind=kint), intent(inout) :: idx(:)
747  integer(kind=kint), intent(in) :: s0, e0
748  integer(kind=kint) :: p0, c0, t0
749  p0 = s0
750  do
751  c0 = 2*p0
752  if (c0 > e0) exit
753  if (c0 < e0) then
754  if (gmat%gid(idx(c0+1)) > gmat%gid(idx(c0))) c0 = c0 + 1
755  endif
756  if (gmat%gid(idx(c0)) <= gmat%gid(idx(p0))) exit
757  t0 = idx(p0)
758  idx(p0) = idx(c0)
759  idx(c0) = t0
760  p0 = c0
761  enddo
762  end subroutine sift_by_gid
763 
764  end subroutine hecmw_mf_dist_gmat_build
765 
771  subroutine mf_gmat_closure(gmat, ng)
772  implicit none
773  type(hecmwst_mf_gmat), intent(inout) :: gmat
774  integer(kind=kint), intent(in) :: ng
775  integer(kind=kint), allocatable :: rp(:), cols(:), fil(:)
776  integer(kind=kint) :: ptr, i, j, k, g, grow, ncols, nmiss
777 
778  ! the k-th row segment of the stream belongs to row g2s(k) of the gid numbering
779  allocate(rp(0:ng), fil(ng))
780  fil(1:ng) = 0
781  ptr = 0
782  do k = 1, ng
783  grow = gmat%g2s(k)
784  fil(grow) = gmat%stream(ptr+1)
785  ptr = ptr + 1 + gmat%stream(ptr+1)
786  enddo
787  rp(0) = 0
788  do i = 1, ng
789  rp(i) = rp(i-1) + fil(i)
790  enddo
791  allocate(cols(max(rp(ng), 1)))
792  ptr = 0
793  do k = 1, ng
794  grow = gmat%g2s(k)
795  ncols = gmat%stream(ptr+1)
796  do j = 1, ncols
797  cols(rp(grow-1)+j) = gmat%stream(ptr+1+j)
798  enddo
799  ptr = ptr + 1 + ncols
800  enddo
801  ! insertion sort within a row (the rows are short)
802  do i = 1, ng
803  do j = rp(i-1)+2, rp(i)
804  g = cols(j)
805  k = j - 1
806  do while (k >= rp(i-1)+1)
807  if (cols(k) <= g) exit
808  cols(k+1) = cols(k)
809  k = k - 1
810  enddo
811  cols(k+1) = g
812  enddo
813  enddo
814  allocate(gmat%xptr(0:ng))
815  gmat%xptr(0:ng) = 0
816  do i = 1, ng
817  do j = rp(i-1)+1, rp(i)
818  g = cols(j)
819  if (.not. found(g, i)) gmat%xptr(g) = gmat%xptr(g) + 1
820  enddo
821  enddo
822  do i = 1, ng
823  gmat%xptr(i) = gmat%xptr(i-1) + gmat%xptr(i)
824  enddo
825  nmiss = gmat%xptr(ng)
826  allocate(gmat%xcol(max(nmiss, 1)))
827  if (nmiss > 0) then
828  ! the outer row ascends, so every xcol row collects its columns ascending
829  fil(1:ng) = 0
830  do i = 1, ng
831  do j = rp(i-1)+1, rp(i)
832  g = cols(j)
833  if (.not. found(g, i)) then
834  fil(g) = fil(g) + 1
835  gmat%xcol(gmat%xptr(g-1) + fil(g)) = i
836  endif
837  enddo
838  enddo
839  endif
840  deallocate(rp, cols, fil)
841 
842  contains
843 
845  logical function found(r0, c0)
846  integer(kind=kint), intent(in) :: r0, c0
847  integer(kind=kint) :: lo0, hi0, mid0
848  found = .false.
849  lo0 = rp(r0-1) + 1
850  hi0 = rp(r0)
851  do while (lo0 <= hi0)
852  mid0 = (lo0 + hi0) / 2
853  if (cols(mid0) == c0) then
854  found = .true.
855  return
856  else if (cols(mid0) < c0) then
857  lo0 = mid0 + 1
858  else
859  hi0 = mid0 - 1
860  endif
861  enddo
862  end function found
863 
864  end subroutine mf_gmat_closure
865 
869  function mf_global_node(hecMESH, gmat, me, j) result(g)
870  implicit none
871  type(hecmwst_local_mesh), intent(in) :: hecmesh
872  type(hecmwst_mf_gmat), intent(in) :: gmat
873  integer(kind=kint), intent(in) :: me, j
874  integer(kind=kint) :: g
875 
876  if (j <= hecmesh%nn_internal) then
877  g = gmat%ndisp(me+1) + j
878  else
879  g = gmat%ndisp(hecmesh%node_ID(2*j) + 1) + hecmesh%node_ID(2*j-1)
880  endif
881  end function mf_global_node
882 
891  subroutine hecmw_mf_dist_gmat_part(sym, map, gmat)
892  implicit none
893  type(hecmwst_mf_symbolic), intent(in) :: sym
894  type(hecmwst_mf_map), intent(in) :: map
895  type(hecmwst_mf_gmat), intent(inout) :: gmat
896  integer(kind=kint), allocatable :: c2s(:), gc(:), bb(:), sptr(:)
897  integer(kind=kint) :: np, me, ng, nd2, i, j, l, m, r, g, b, ptr, ncols, grow, maxcols
898  integer(kind=kint) :: ka, nl, nu, nkeep, nrecv, pos, r0, nr0, d
899 
900  np = map%nprocs
901  me = map%myrank
902  ng = gmat%ndisp(np+1)
903  nd2 = gmat%mat%NDOF * gmat%mat%NDOF
904  if (associated(gmat%mat%indexL)) then
905  deallocate(gmat%mat%indexL, gmat%mat%indexU, gmat%mat%itemL, gmat%mat%itemU)
906  endif
907  allocate(c2s(sym%nnode))
908  call mf_gmat_c2s(sym, c2s)
909 
910  ! count the retained lower/upper split per row and the received blocks per source
911  allocate(gmat%rcnt(np), gmat%mat%indexL(0:ng), gmat%mat%indexU(0:ng))
912  gmat%rcnt(1:np) = 0
913  gmat%mat%indexL(0:ng) = 0
914  gmat%mat%indexU(0:ng) = 0
915  maxcols = 0
916  ptr = 0
917  do r = 1, np
918  do i = 1, gmat%nn(r)
919  grow = gmat%g2s(gmat%ndisp(r) + i)
920  ka = sym%invp(grow)
921  ncols = gmat%stream(ptr+1)
922  maxcols = max(maxcols, ncols + gmat%xptr(grow) - gmat%xptr(grow-1))
923  if (mine(ka, ka)) gmat%rcnt(r) = gmat%rcnt(r) + 1
924  do j = 1, ncols
925  g = gmat%stream(ptr+1+j)
926  if (mine(ka, sym%invp(g))) then
927  gmat%rcnt(r) = gmat%rcnt(r) + 1
928  if (g < grow) then
929  gmat%mat%indexL(grow) = gmat%mat%indexL(grow) + 1
930  else
931  gmat%mat%indexU(grow) = gmat%mat%indexU(grow) + 1
932  endif
933  endif
934  enddo
935  ! the closure positions are retained like their mirrored partners but receive no block
936  do j = gmat%xptr(grow-1)+1, gmat%xptr(grow)
937  g = gmat%xcol(j)
938  if (mine(ka, sym%invp(g))) then
939  if (g < grow) then
940  gmat%mat%indexL(grow) = gmat%mat%indexL(grow) + 1
941  else
942  gmat%mat%indexU(grow) = gmat%mat%indexU(grow) + 1
943  endif
944  endif
945  enddo
946  ptr = ptr + 1 + ncols
947  enddo
948  enddo
949  do i = 1, ng
950  gmat%mat%indexL(i) = gmat%mat%indexL(i-1) + gmat%mat%indexL(i)
951  gmat%mat%indexU(i) = gmat%mat%indexU(i-1) + gmat%mat%indexU(i)
952  enddo
953  gmat%mat%NPL = gmat%mat%indexL(ng)
954  gmat%mat%NPU = gmat%mat%indexU(ng)
955  allocate(gmat%mat%itemL(max(gmat%mat%NPL, 1)), gmat%mat%itemU(max(gmat%mat%NPU, 1)))
956  allocate(gmat%mat%D(int(ng, 8)*nd2))
957  allocate(gmat%mat%AL(max(int(gmat%mat%NPL, 8)*nd2, 1_8)))
958  allocate(gmat%mat%AU(max(int(gmat%mat%NPU, 8)*nd2, 1_8)))
959  ! the closure positions are never overwritten by the value exchange, so they must be zero
960  gmat%mat%D(:) = 0.0d0
961  gmat%mat%AL(:) = 0.0d0
962  gmat%mat%AU(:) = 0.0d0
963 
964  ! second sweep: sort the retained columns of a row ascending and record the landing
965  ! slot of every received block, following the stream order of its source
966  nrecv = 0
967  do r = 1, np
968  nrecv = nrecv + gmat%rcnt(r)
969  enddo
970  allocate(gmat%rdst(max(nrecv, 1)), gc(max(maxcols, 1)), bb(max(maxcols, 1)))
971  ptr = 0
972  b = 0
973  do r = 1, np
974  do i = 1, gmat%nn(r)
975  grow = gmat%g2s(gmat%ndisp(r) + i)
976  ka = sym%invp(grow)
977  ncols = gmat%stream(ptr+1)
978  if (mine(ka, ka)) then
979  b = b + 1
980  gmat%rdst(b) = gmat%mat%NPL + gmat%mat%NPU + grow
981  endif
982  nkeep = 0
983  do j = 1, ncols
984  g = gmat%stream(ptr+1+j)
985  if (mine(ka, sym%invp(g))) then
986  nkeep = nkeep + 1
987  b = b + 1
988  gc(nkeep) = g
989  bb(nkeep) = b
990  endif
991  enddo
992  ! retained closure positions take an item slot but no landing slot (bb = 0)
993  do j = gmat%xptr(grow-1)+1, gmat%xptr(grow)
994  g = gmat%xcol(j)
995  if (mine(ka, sym%invp(g))) then
996  nkeep = nkeep + 1
997  gc(nkeep) = g
998  bb(nkeep) = 0
999  endif
1000  enddo
1001  ptr = ptr + 1 + ncols
1002  ! insertion sort by the global column id (unique within a row)
1003  do j = 2, nkeep
1004  g = gc(j)
1005  m = bb(j)
1006  l = j - 1
1007  do while (l >= 1)
1008  if (gc(l) <= g) exit
1009  gc(l+1) = gc(l)
1010  bb(l+1) = bb(l)
1011  l = l - 1
1012  enddo
1013  gc(l+1) = g
1014  bb(l+1) = m
1015  enddo
1016  nl = 0
1017  nu = 0
1018  do j = 1, nkeep
1019  if (gc(j) < grow) then
1020  nl = nl + 1
1021  pos = gmat%mat%indexL(grow-1) + nl
1022  gmat%mat%itemL(pos) = gc(j)
1023  if (bb(j) > 0) gmat%rdst(bb(j)) = pos
1024  else
1025  nu = nu + 1
1026  pos = gmat%mat%indexU(grow-1) + nu
1027  gmat%mat%itemU(pos) = gc(j)
1028  if (bb(j) > 0) gmat%rdst(bb(j)) = gmat%mat%NPL + pos
1029  endif
1030  enddo
1031  enddo
1032  enddo
1033 
1034  ! send side: the blocks of my stream segment by destination rank set, kept in the
1035  ! stream order within a destination
1036  allocate(gmat%scnt(np), sptr(np))
1037  gmat%scnt(1:np) = 0
1038  ptr = 0
1039  do r = 1, me
1040  ptr = ptr + gmat%vblk(r)
1041  enddo
1042  b = ptr
1043  do i = 1, gmat%nn(me+1)
1044  grow = gmat%g2s(gmat%ndisp(me+1) + i)
1045  ka = sym%invp(grow)
1046  ncols = gmat%stream(ptr+1)
1047  call destrange(ka, ka, r0, nr0)
1048  gmat%scnt(r0+1:r0+nr0) = gmat%scnt(r0+1:r0+nr0) + 1
1049  do j = 1, ncols
1050  call destrange(ka, sym%invp(gmat%stream(ptr+1+j)), r0, nr0)
1051  gmat%scnt(r0+1:r0+nr0) = gmat%scnt(r0+1:r0+nr0) + 1
1052  enddo
1053  ptr = ptr + 1 + ncols
1054  enddo
1055  sptr(1) = 0
1056  do r = 2, np
1057  sptr(r) = sptr(r-1) + gmat%scnt(r-1)
1058  enddo
1059  i = sptr(np) + gmat%scnt(np)
1060  allocate(gmat%ssel(max(i, 1)))
1061  ptr = b
1062  b = 0
1063  do i = 1, gmat%nn(me+1)
1064  grow = gmat%g2s(gmat%ndisp(me+1) + i)
1065  ka = sym%invp(grow)
1066  ncols = gmat%stream(ptr+1)
1067  b = b + 1
1068  call destrange(ka, ka, r0, nr0)
1069  do d = r0 + 1, r0 + nr0
1070  sptr(d) = sptr(d) + 1
1071  gmat%ssel(sptr(d)) = b
1072  enddo
1073  do j = 1, ncols
1074  b = b + 1
1075  call destrange(ka, sym%invp(gmat%stream(ptr+1+j)), r0, nr0)
1076  do d = r0 + 1, r0 + nr0
1077  sptr(d) = sptr(d) + 1
1078  gmat%ssel(sptr(d)) = b
1079  enddo
1080  enddo
1081  ptr = ptr + 1 + ncols
1082  enddo
1083  deallocate(gmat%stream, gmat%xptr, gmat%xcol, c2s, gc, bb, sptr)
1084 
1085  contains
1086 
1088  logical function mine(ka0, kb0)
1089  integer(kind=kint), intent(in) :: ka0, kb0
1090  integer(kind=kint) :: s0
1091  s0 = c2s(min(ka0, kb0))
1092  mine = me >= map%rbeg(s0) .and. me < map%rbeg(s0) + map%rcnt(s0)
1093  end function mine
1094 
1096  subroutine destrange(ka0, kb0, r1, nr1)
1097  integer(kind=kint), intent(in) :: ka0, kb0
1098  integer(kind=kint), intent(out) :: r1, nr1
1099  integer(kind=kint) :: s0
1100  s0 = c2s(min(ka0, kb0))
1101  r1 = map%rbeg(s0)
1102  nr1 = map%rcnt(s0)
1103  end subroutine destrange
1104 
1105  end subroutine hecmw_mf_dist_gmat_part
1106 
1111  subroutine hecmw_mf_dist_gmat_vals(hecMAT, gmat)
1112  implicit none
1113  type(hecmwst_matrix), intent(in) :: hecmat
1114  type(hecmwst_mf_gmat), intent(inout) :: gmat
1115  real(kind=kreal), allocatable :: vbuf(:), sbuf(:), rbuf(:)
1116  integer(kind=kint), allocatable :: scs(:), sdisp(:), rcs(:), rdisp(:)
1117  integer(kind=kint) :: np, me, comm, nd2, n, i, k, r, t, nsend, nrecv
1118  integer(kind=8) :: ptr, b, base
1119 
1120  np = hecmw_comm_get_size()
1121  me = hecmw_comm_get_rank()
1122  comm = hecmw_comm_get_comm()
1123  gmat%mat%symmetric = hecmat%symmetric
1124  nd2 = hecmat%NDOF * hecmat%NDOF
1125  n = hecmat%N
1126  allocate(vbuf(max(int(gmat%vblk(me+1), 8)*nd2, 1_8)))
1127  ptr = 0
1128  do i = 1, n
1129  vbuf(ptr+1:ptr+nd2) = hecmat%D(int(i-1, 8)*nd2+1:int(i, 8)*nd2)
1130  ptr = ptr + nd2
1131  do k = hecmat%indexL(i-1)+1, hecmat%indexL(i)
1132  vbuf(ptr+1:ptr+nd2) = hecmat%AL(int(k-1, 8)*nd2+1:int(k, 8)*nd2)
1133  ptr = ptr + nd2
1134  enddo
1135  do k = hecmat%indexU(i-1)+1, hecmat%indexU(i)
1136  vbuf(ptr+1:ptr+nd2) = hecmat%AU(int(k-1, 8)*nd2+1:int(k, 8)*nd2)
1137  ptr = ptr + nd2
1138  enddo
1139  enddo
1140  allocate(scs(np), sdisp(np), rcs(np), rdisp(np))
1141  nsend = 0
1142  nrecv = 0
1143  do r = 1, np
1144  scs(r) = gmat%scnt(r) * nd2
1145  rcs(r) = gmat%rcnt(r) * nd2
1146  sdisp(r) = nsend * nd2
1147  rdisp(r) = nrecv * nd2
1148  nsend = nsend + gmat%scnt(r)
1149  nrecv = nrecv + gmat%rcnt(r)
1150  enddo
1151  allocate(sbuf(max(int(nsend, 8)*nd2, 1_8)), rbuf(max(int(nrecv, 8)*nd2, 1_8)))
1152  do i = 1, nsend
1153  b = int(gmat%ssel(i) - 1, 8)*nd2
1154  base = int(i-1, 8)*nd2
1155  sbuf(base+1:base+nd2) = vbuf(b+1:b+nd2)
1156  enddo
1157  call hecmw_alltoallv_real(sbuf, scs, sdisp, rbuf, rcs, rdisp, comm)
1158  do b = 1, nrecv
1159  t = gmat%rdst(b)
1160  base = (b-1)*nd2
1161  if (t <= gmat%mat%NPL) then
1162  gmat%mat%AL(int(t-1, 8)*nd2+1:int(t, 8)*nd2) = rbuf(base+1:base+nd2)
1163  else if (t <= gmat%mat%NPL + gmat%mat%NPU) then
1164  t = t - gmat%mat%NPL
1165  gmat%mat%AU(int(t-1, 8)*nd2+1:int(t, 8)*nd2) = rbuf(base+1:base+nd2)
1166  else
1167  t = t - gmat%mat%NPL - gmat%mat%NPU
1168  gmat%mat%D(int(t-1, 8)*nd2+1:int(t, 8)*nd2) = rbuf(base+1:base+nd2)
1169  endif
1170  enddo
1171  deallocate(vbuf, sbuf, rbuf, scs, sdisp, rcs, rdisp)
1172  end subroutine hecmw_mf_dist_gmat_vals
1173 
1177  subroutine hecmw_mf_dist_gmat_words(gmat, wpart, wrepl)
1178  implicit none
1179  type(hecmwst_mf_gmat), intent(in) :: gmat
1180  integer(kind=8), intent(out) :: wpart, wrepl
1181  integer(kind=8) :: ng, ni, nd2
1182 
1183  ng = size(gmat%mat%indexL, kind=8) - 1
1184  nd2 = int(gmat%mat%NDOF, 8)**2
1185  wpart = size(gmat%mat%D, kind=8) + size(gmat%mat%AL, kind=8) + size(gmat%mat%AU, kind=8)
1186  ni = 2*(ng+1) + size(gmat%mat%itemL, kind=8) + size(gmat%mat%itemU, kind=8) &
1187  + size(gmat%ssel, kind=8) + size(gmat%rdst, kind=8) &
1188  + size(gmat%scnt, kind=8) + size(gmat%rcnt, kind=8) + 3*size(gmat%nn, kind=8) + 1
1189  wpart = wpart + (ni + 1)/2
1190  wrepl = int(gmat%nblk, 8)*nd2 + (int(gmat%nblk, 8) - ng + 2*(ng+1) + int(gmat%nblk, 8) + 1)/2
1191  end subroutine hecmw_mf_dist_gmat_words
1192 
1194  subroutine mf_gmat_c2s(sym, c2s)
1195  implicit none
1196  type(hecmwst_mf_symbolic), intent(in) :: sym
1197  integer(kind=kint), intent(out) :: c2s(:)
1198  integer(kind=kint) :: s, k
1199 
1200  do s = 1, sym%nsuper
1201  do k = sym%sptr(s), sym%sptr(s+1) - 1
1202  c2s(k) = s
1203  enddo
1204  enddo
1205  end subroutine mf_gmat_c2s
1206 
1215  subroutine hecmw_mf_dist_gmat_extract(full, sym, map, part)
1216  implicit none
1217  type(hecmwst_matrix), intent(in) :: full
1218  type(hecmwst_mf_symbolic), intent(in) :: sym
1219  type(hecmwst_mf_map), intent(in) :: map
1220  type(hecmwst_matrix), intent(inout) :: part
1221  integer(kind=kint), allocatable :: c2s(:)
1222  integer(kind=kint) :: me, nd2, ng, i, k, ka, nl, nu
1223  integer(kind=8) :: bs, bd
1224 
1225  me = map%myrank
1226  nd2 = full%NDOF * full%NDOF
1227  ng = full%NP
1228  part%N = full%N
1229  part%NP = full%NP
1230  part%NDOF = full%NDOF
1231  part%symmetric = full%symmetric
1232  allocate(c2s(sym%nnode))
1233  call mf_gmat_c2s(sym, c2s)
1234  allocate(part%indexL(0:ng), part%indexU(0:ng))
1235  part%indexL(0) = 0
1236  part%indexU(0) = 0
1237  do i = 1, ng
1238  ka = sym%invp(i)
1239  nl = 0
1240  do k = full%indexL(i-1)+1, full%indexL(i)
1241  if (mine(ka, sym%invp(full%itemL(k)))) nl = nl + 1
1242  enddo
1243  nu = 0
1244  do k = full%indexU(i-1)+1, full%indexU(i)
1245  if (mine(ka, sym%invp(full%itemU(k)))) nu = nu + 1
1246  enddo
1247  part%indexL(i) = part%indexL(i-1) + nl
1248  part%indexU(i) = part%indexU(i-1) + nu
1249  enddo
1250  part%NPL = part%indexL(ng)
1251  part%NPU = part%indexU(ng)
1252  allocate(part%itemL(max(part%NPL, 1)), part%itemU(max(part%NPU, 1)))
1253  allocate(part%D(int(ng, 8)*nd2))
1254  allocate(part%AL(max(int(part%NPL, 8)*nd2, 1_8)))
1255  allocate(part%AU(max(int(part%NPU, 8)*nd2, 1_8)))
1256  nullify(part%B, part%X, part%A, part%indexA, part%itemA)
1257  nl = 0
1258  nu = 0
1259  do i = 1, ng
1260  ka = sym%invp(i)
1261  bd = int(i-1, 8)*nd2
1262  if (mine(ka, ka)) then
1263  part%D(bd+1:bd+nd2) = full%D(bd+1:bd+nd2)
1264  else
1265  part%D(bd+1:bd+nd2) = 0.0d0
1266  endif
1267  do k = full%indexL(i-1)+1, full%indexL(i)
1268  if (.not. mine(ka, sym%invp(full%itemL(k)))) cycle
1269  nl = nl + 1
1270  part%itemL(nl) = full%itemL(k)
1271  bs = int(k-1, 8)*nd2
1272  bd = int(nl-1, 8)*nd2
1273  part%AL(bd+1:bd+nd2) = full%AL(bs+1:bs+nd2)
1274  enddo
1275  do k = full%indexU(i-1)+1, full%indexU(i)
1276  if (.not. mine(ka, sym%invp(full%itemU(k)))) cycle
1277  nu = nu + 1
1278  part%itemU(nu) = full%itemU(k)
1279  bs = int(k-1, 8)*nd2
1280  bd = int(nu-1, 8)*nd2
1281  part%AU(bd+1:bd+nd2) = full%AU(bs+1:bs+nd2)
1282  enddo
1283  enddo
1284  deallocate(c2s)
1285 
1286  contains
1287 
1289  logical function mine(ka0, kb0)
1290  integer(kind=kint), intent(in) :: ka0, kb0
1291  integer(kind=kint) :: s0
1292  s0 = c2s(min(ka0, kb0))
1293  mine = me >= map%rbeg(s0) .and. me < map%rbeg(s0) + map%rcnt(s0)
1294  end function mine
1295 
1296  end subroutine hecmw_mf_dist_gmat_extract
1297 
1300  subroutine hecmw_mf_dist_gather_vec(gmat, v, gv)
1301  implicit none
1302  type(hecmwst_mf_gmat), intent(in) :: gmat
1303  real(kind=kreal), intent(in) :: v(:)
1304  real(kind=kreal), intent(out) :: gv(:)
1305  real(kind=kreal), allocatable :: vg(:)
1306  integer(kind=kint), allocatable :: vlen(:), vdisp(:)
1307  integer(kind=kint) :: np, me, comm, nd, r, k, d, g
1308 
1309  np = hecmw_comm_get_size()
1310  me = hecmw_comm_get_rank()
1311  comm = hecmw_comm_get_comm()
1312  nd = gmat%mat%NDOF
1313  allocate(vlen(np), vdisp(np), vg(gmat%ndisp(np+1)*nd))
1314  do r = 1, np
1315  vlen(r) = gmat%nn(r) * nd
1316  vdisp(r) = gmat%ndisp(r) * nd
1317  enddo
1318  call hecmw_allgatherv_real(v, vlen(me+1), vg, vlen, vdisp, comm)
1319  ! scatter the gathered layout into the gid row numbering of the matrix
1320  do k = 1, gmat%ndisp(np+1)
1321  g = gmat%g2s(k)
1322  do d = 1, nd
1323  gv((g-1)*nd + d) = vg((k-1)*nd + d)
1324  enddo
1325  enddo
1326  deallocate(vlen, vdisp, vg)
1327  end subroutine hecmw_mf_dist_gather_vec
1328 
1330  implicit none
1331  type(hecmwst_mf_gmat), intent(inout) :: gmat
1332 
1333  gmat%nblk = 0
1334  if (allocated(gmat%nn)) then
1335  deallocate(gmat%nn, gmat%ndisp, gmat%vblk)
1336  if (allocated(gmat%stream)) deallocate(gmat%stream)
1337  if (allocated(gmat%xptr)) deallocate(gmat%xptr, gmat%xcol)
1338  if (allocated(gmat%gid)) deallocate(gmat%gid)
1339  if (allocated(gmat%g2s)) deallocate(gmat%g2s)
1340  if (allocated(gmat%scnt)) deallocate(gmat%scnt, gmat%ssel, gmat%rcnt, gmat%rdst)
1341  if (associated(gmat%mat%indexL)) then
1342  deallocate(gmat%mat%indexL, gmat%mat%indexU, gmat%mat%itemL, gmat%mat%itemU)
1343  endif
1344  if (associated(gmat%mat%D)) deallocate(gmat%mat%D, gmat%mat%AL, gmat%mat%AU)
1345  nullify(gmat%mat%indexL, gmat%mat%indexU, gmat%mat%itemL, gmat%mat%itemU)
1346  nullify(gmat%mat%D, gmat%mat%AL, gmat%mat%AU)
1347  endif
1348  end subroutine hecmw_mf_dist_gmat_finalize
1349 
1350 end module hecmw_mf_dist
MPI distribution layer of the multifrontal solver: the supernode-to-rank mapping and the broadcast of...
subroutine, public hecmw_mf_dist_gmat_finalize(gmat)
subroutine, public hecmw_mf_dist_gmat_extract(full, sym, map, part)
Extract from the replicated matrix the part this rank reads under the distribution: the block pairs o...
subroutine, public hecmw_mf_dist_rowtiles(sym, map, tile, s, ndel, ncbt, ctb, towner)
Contribution row tiles of upper front s and their owning ranks. The boundaries ctb (0:ncbt) are offse...
subroutine, public hecmw_mf_dist_gather_vec(gmat, v, gv)
Gather the internal parts of a distributed nodal vector into the replicated global vector,...
integer(kind=kint) function, public hecmw_mf_dist_fsrank(map, s, pr, pc, i, j)
Owning rank of fully summed tile (i, j), j <= i, of upper front s on its pr x pc grid: block cyclic o...
subroutine, public hecmw_mf_dist_fsgrid(map, s, ntc, pr, pc)
2D process grid pr x pc of the fully summed part of upper front s, from its fully summed tile count n...
subroutine, public hecmw_mf_dist_map_build(sym, map)
Build the mapping from the symbolic structure. The roots share all ranks (several roots split them pr...
subroutine, public hecmw_mf_dist_symbolic_bcast(sym, root)
Broadcast the symbolic structure built on the root rank to all ranks. The int8 estimates (factor_nnz,...
subroutine, public hecmw_mf_dist_gmat_part(sym, map, gmat)
Derive from the mapping the partial profile of this rank and the value routing, and drop the gathered...
subroutine, public hecmw_mf_dist_gmat_words(gmat, wpart, wrepl)
Words this rank holds for the matrix (the values with the integer structure and routing at two intege...
subroutine, public hecmw_mf_dist_gmat_vals(hecMAT, gmat)
Move the values of the internal rows to their holding ranks through the routing of hecmw_mf_dist_gmat...
subroutine, public hecmw_mf_dist_map_finalize(map)
subroutine, public hecmw_mf_dist_gmat_build(hecMESH, hecMAT, gmat)
Gather the nonzero structure of the internal rows of every rank. The stream carries,...
Symbolic factorization (elimination tree, column counts, supernodes, row structure) for the multifron...
subroutine, public hecmw_mf_symbolic_finalize(sym)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=kint) function hecmw_comm_get_size()
integer(kind=4), parameter kint
integer(kind=kint) function hecmw_comm_get_comm()
integer(kind=4), parameter kreal
integer(kind=kint) function hecmw_comm_get_rank()
subroutine hecmw_allgatherv_int(sbuf, sc, rbuf, rcs, disp, comm)
subroutine hecmw_alltoallv_real(sbuf, scs, sdisp, rbuf, rcs, rdisp, comm)
subroutine hecmw_allgatherv_real(sbuf, sc, rbuf, rcs, disp, comm)
subroutine hecmw_bcast_i_comm(val, n, nbase, comm)
subroutine hecmw_allgather_int_1(sval, rbuf, comm)