FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
hecmw_mf_symbolic.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 !-------------------------------------------------------------------------------
15  use hecmw_util
16  use hecmw_mf_graph
17  implicit none
18 
19  private
20  public :: hecmwst_mf_symbolic
21  public :: hecmw_mf_symbolic_build
23  public :: hecmw_mf_symbolic_check
24  public :: hecmw_mf_symbolic_print
26 
32  type hecmwst_mf_symbolic
33  integer(kind=kint) :: nnode = 0
34  integer(kind=kint) :: nsuper = 0
35  integer(kind=kint) :: nmerge = 0
36  integer(kind=kint), allocatable :: perm(:)
37  integer(kind=kint), allocatable :: invp(:)
38  integer(kind=kint), allocatable :: ndof(:)
39  integer(kind=kint), allocatable :: parent(:)
40  integer(kind=kint), allocatable :: colcnt(:)
41  integer(kind=kint), allocatable :: sptr(:)
42  integer(kind=kint), allocatable :: sparent(:)
43  integer(kind=kint), allocatable :: rptr(:)
44  integer(kind=kint), allocatable :: rlist(:)
46  integer(kind=kint), allocatable :: cmap_ptr(:)
47  integer(kind=kint), allocatable :: cmap(:)
49  integer(kind=kint) :: max_front = 0
50  integer(kind=8) :: factor_nnz = 0
51  integer(kind=8) :: flops = 0
52  end type hecmwst_mf_symbolic
53 
54 contains
55 
61  subroutine hecmw_mf_symbolic_build(graph, perm, relax_nodes, sym)
62  implicit none
63  type(hecmwst_mf_graph), intent(in) :: graph
64  integer(kind=kint), intent(in) :: perm(:)
65  integer(kind=kint), intent(in) :: relax_nodes
66  type(hecmwst_mf_symbolic), intent(out) :: sym
67  integer(kind=kint), allocatable :: post(:)
68  integer(kind=kint) :: n, k
69 
70  n = graph%nnode
71  sym%nnode = n
72  allocate(sym%perm(n), sym%invp(n), sym%ndof(n), sym%parent(n), sym%colcnt(n))
73  allocate(post(n))
74  sym%perm(1:n) = perm(1:n)
75  do k = 1, n
76  sym%invp(sym%perm(k)) = k
77  enddo
78 
79  call mf_etree(graph, sym%perm, sym%invp, sym%parent)
80  call mf_postorder(n, sym%parent, post)
81  call mf_relabel(n, post, sym%perm, sym%invp, sym%parent)
82  call mf_colcounts(graph, sym%perm, sym%invp, sym%parent, sym%colcnt)
83  call mf_supernodes(n, sym%parent, sym%colcnt, relax_nodes, sym%nsuper, sym%sptr, sym%sparent, post, sym%nmerge)
84  call mf_relabel(n, post, sym%perm, sym%invp, sym%parent, sym%colcnt)
85  do k = 1, n
86  sym%ndof(k) = graph%ndof(sym%perm(k))
87  enddo
88  call mf_rowstruct(graph, sym)
89  call mf_estimate(sym)
90  deallocate(post)
91  end subroutine hecmw_mf_symbolic_build
92 
94  implicit none
95  type(hecmwst_mf_symbolic), intent(inout) :: sym
96 
97  sym%nnode = 0
98  sym%nsuper = 0
99  if (allocated(sym%perm)) deallocate(sym%perm)
100  if (allocated(sym%invp)) deallocate(sym%invp)
101  if (allocated(sym%ndof)) deallocate(sym%ndof)
102  if (allocated(sym%parent)) deallocate(sym%parent)
103  if (allocated(sym%colcnt)) deallocate(sym%colcnt)
104  if (allocated(sym%sptr)) deallocate(sym%sptr)
105  if (allocated(sym%sparent)) deallocate(sym%sparent)
106  if (allocated(sym%rptr)) deallocate(sym%rptr)
107  if (allocated(sym%rlist)) deallocate(sym%rlist)
108  if (allocated(sym%cmap_ptr)) deallocate(sym%cmap_ptr)
109  if (allocated(sym%cmap)) deallocate(sym%cmap)
110  end subroutine hecmw_mf_symbolic_finalize
111 
116  subroutine mf_etree(graph, perm, invp, parent)
117  implicit none
118  type(hecmwst_mf_graph), intent(in) :: graph
119  integer(kind=kint), intent(in) :: perm(:)
120  integer(kind=kint), intent(in) :: invp(:)
121  integer(kind=kint), intent(out) :: parent(:)
122  integer(kind=kint), allocatable :: setp(:)
123  integer(kind=kint) :: n, k, u, r, p
124 
125  n = graph%nnode
126  allocate(setp(n))
127  parent(1:n) = 0
128  do k = 1, n
129  setp(k) = k
130  enddo
131  do k = 1, n
132  do p = graph%xadj(perm(k)), graph%xadj(perm(k)+1)-1
133  u = invp(graph%adjncy(p))
134  if (u >= k) cycle
135  r = u
136  do while (setp(r) /= r)
137  setp(r) = setp(setp(r))
138  r = setp(r)
139  enddo
140  if (r /= k) then
141  parent(r) = k
142  setp(r) = k
143  endif
144  enddo
145  enddo
146  deallocate(setp)
147  end subroutine mf_etree
148 
150  subroutine mf_postorder(n, parent, post)
151  implicit none
152  integer(kind=kint), intent(in) :: n
153  integer(kind=kint), intent(in) :: parent(:)
154  integer(kind=kint), intent(out) :: post(:)
155  integer(kind=kint), allocatable :: cptr(:), clist(:), cur(:), stk(:)
156  integer(kind=kint) :: j, k, p, v, c, top
157 
158  ! the children of v are clist(cptr(v-1)+1 : cptr(v)), ascending because the fill
159  ! walks j upward; cur(v) is the next child of v the walk has not descended into
160  allocate(cptr(0:n), clist(n), cur(n), stk(n))
161  cptr(0:n) = 0
162  do j = 1, n
163  p = parent(j)
164  if (p /= 0) cptr(p) = cptr(p) + 1
165  enddo
166  do j = 1, n
167  cptr(j) = cptr(j-1) + cptr(j)
168  enddo
169  cur(1:n) = 0
170  do j = 1, n
171  p = parent(j)
172  if (p == 0) cycle
173  cur(p) = cur(p) + 1
174  clist(cptr(p-1) + cur(p)) = j
175  enddo
176  k = 0
177  do j = 1, n
178  if (parent(j) /= 0) cycle
179  top = 1
180  stk(1) = j
181  cur(j) = cptr(j-1)
182  do while (top > 0)
183  v = stk(top)
184  if (cur(v) < cptr(v)) then
185  cur(v) = cur(v) + 1
186  c = clist(cur(v))
187  top = top + 1
188  stk(top) = c
189  cur(c) = cptr(c-1)
190  else
191  top = top - 1
192  k = k + 1
193  post(k) = v
194  endif
195  enddo
196  enddo
197  deallocate(cptr, clist, cur, stk)
198  end subroutine mf_postorder
199 
201  subroutine mf_relabel(n, post, perm, invp, parent, colcnt)
202  implicit none
203  integer(kind=kint), intent(in) :: n
204  integer(kind=kint), intent(in) :: post(:)
205  integer(kind=kint), intent(inout) :: perm(:)
206  integer(kind=kint), intent(inout) :: invp(:)
207  integer(kind=kint), intent(inout) :: parent(:)
208  integer(kind=kint), intent(inout), optional :: colcnt(:)
209  integer(kind=kint), allocatable :: newpos(:), work(:)
210  integer(kind=kint) :: k
211 
212  allocate(newpos(n), work(n))
213  do k = 1, n
214  newpos(post(k)) = k
215  enddo
216  do k = 1, n
217  work(k) = perm(post(k))
218  enddo
219  perm(1:n) = work(1:n)
220  do k = 1, n
221  invp(perm(k)) = k
222  enddo
223  do k = 1, n
224  if (parent(post(k)) == 0) then
225  work(k) = 0
226  else
227  work(k) = newpos(parent(post(k)))
228  endif
229  enddo
230  parent(1:n) = work(1:n)
231  if (present(colcnt)) then
232  do k = 1, n
233  work(k) = colcnt(post(k))
234  enddo
235  colcnt(1:n) = work(1:n)
236  endif
237  deallocate(newpos, work)
238  end subroutine mf_relabel
239 
246  subroutine mf_colcounts(graph, perm, invp, parent, colcnt)
247  implicit none
248  type(hecmwst_mf_graph), intent(in) :: graph
249  integer(kind=kint), intent(in) :: perm(:)
250  integer(kind=kint), intent(in) :: invp(:)
251  integer(kind=kint), intent(in) :: parent(:)
252  integer(kind=kint), intent(out) :: colcnt(:)
253  integer(kind=kint), allocatable :: fdesc(:), maxfd(:), lastleaf(:), setp(:)
254  integer(kind=kint) :: n, j, i, p, q, w
255 
256  n = graph%nnode
257  allocate(fdesc(n), maxfd(n), lastleaf(n), setp(n))
258  ! with a postordered tree the subtree of j is the contiguous range fdesc(j)..j, so
259  ! the first descendant is the minimum over the children (available when j is reached)
260  do j = 1, n
261  fdesc(j) = j
262  enddo
263  do j = 1, n
264  p = parent(j)
265  if (p /= 0) fdesc(p) = min(fdesc(p), fdesc(j))
266  enddo
267  do j = 1, n
268  if (fdesc(j) == j) then
269  colcnt(j) = 1
270  else
271  colcnt(j) = 0
272  endif
273  maxfd(j) = 0
274  lastleaf(j) = 0
275  setp(j) = j
276  enddo
277  do j = 1, n
278  p = parent(j)
279  ! the parent sees j's whole subtree except j itself through the summing pass
280  if (p /= 0) colcnt(p) = colcnt(p) - 1
281  do i = graph%xadj(perm(j)), graph%xadj(perm(j)+1)-1
282  q = invp(graph%adjncy(i))
283  if (q <= j) cycle
284  ! j is a leaf of row q's skeleton when no earlier leaf reached into j's subtree
285  if (fdesc(j) <= maxfd(q)) cycle
286  maxfd(q) = fdesc(j)
287  colcnt(j) = colcnt(j) + 1
288  if (lastleaf(q) /= 0) then
289  w = lca(lastleaf(q))
290  colcnt(w) = colcnt(w) - 1
291  endif
292  lastleaf(q) = j
293  enddo
294  ! j's set joins the parent: the representative of a processed column is the lowest
295  ! unprocessed ancestor, which is the least common ancestor with any later leaf
296  if (p /= 0) setp(j) = p
297  enddo
298  do j = 1, n
299  if (parent(j) /= 0) colcnt(parent(j)) = colcnt(parent(j)) + colcnt(j)
300  enddo
301  deallocate(fdesc, maxfd, lastleaf, setp)
302 
303  contains
304 
306  integer(kind=kint) function lca(v)
307  integer(kind=kint), intent(in) :: v
308  integer(kind=kint) :: r
309  r = v
310  do while (setp(r) /= r)
311  setp(r) = setp(setp(r))
312  r = setp(r)
313  enddo
314  lca = r
315  end function lca
316 
317  end subroutine mf_colcounts
318 
321  subroutine mf_supernodes(n, parent, colcnt, relax_nodes, nsuper, sptr, sparent, post, nmerge)
322  implicit none
323  integer(kind=kint), intent(in) :: n
324  integer(kind=kint), intent(in) :: parent(:)
325  integer(kind=kint), intent(in) :: colcnt(:)
326  integer(kind=kint), intent(in) :: relax_nodes
327  integer(kind=kint), intent(out) :: nsuper
328  integer(kind=kint), allocatable, intent(out) :: sptr(:)
329  integer(kind=kint), allocatable, intent(out) :: sparent(:)
330  integer(kind=kint), intent(out) :: post(:)
331  integer(kind=kint), intent(out) :: nmerge
332  integer(kind=kint), allocatable :: nchild(:), superof(:), fptr(:), fparent(:), rep(:), size(:)
333  integer(kind=kint), allocatable :: mid(:), mcols_ptr(:), mcols(:), mparent(:), morder(:), newid(:)
334  integer(kind=kint) :: nfund, k, s, p, m, nm, l, c
335 
336  allocate(nchild(n), superof(n))
337  nchild(1:n) = 0
338  do k = 1, n
339  if (parent(k) /= 0) nchild(parent(k)) = nchild(parent(k)) + 1
340  enddo
341  nfund = 0
342  do k = 1, n
343  if (k > 1) then
344  if (parent(k-1) == k .and. colcnt(k-1) == colcnt(k) + 1 .and. nchild(k) == 1) then
345  superof(k) = nfund
346  cycle
347  endif
348  endif
349  nfund = nfund + 1
350  superof(k) = nfund
351  enddo
352  allocate(fptr(nfund+1), fparent(nfund), rep(nfund), size(nfund))
353  fptr(1) = 1
354  do k = 1, n
355  fptr(superof(k)+1) = k + 1
356  enddo
357  do s = 1, nfund
358  p = parent(fptr(s+1)-1)
359  if (p == 0) then
360  fparent(s) = 0
361  else
362  fparent(s) = superof(p)
363  endif
364  rep(s) = s
365  size(s) = fptr(s+1) - fptr(s)
366  enddo
367 
368  ! greedy bottom-up merge; children are processed before their parent by the postorder
369  nmerge = 0
370  do s = 1, nfund
371  p = fparent(s)
372  if (p == 0) cycle
373  if (size(s) + size(p) <= relax_nodes) then
374  rep(s) = p
375  size(p) = size(p) + size(s)
376  nmerge = nmerge + 1
377  endif
378  enddo
379 
380  ! merged supernodes are the fixed points of rep; mid numbers them in increasing order
381  allocate(mid(nfund))
382  nm = 0
383  do s = 1, nfund
384  if (rep(s) == s) then
385  nm = nm + 1
386  mid(s) = nm
387  else
388  mid(s) = 0
389  endif
390  enddo
391  do s = 1, nfund
392  p = s
393  do while (rep(p) /= p)
394  p = rep(p)
395  enddo
396  mid(s) = mid(p)
397  enddo
398  allocate(mparent(nm), mcols_ptr(nm+1), mcols(n), morder(nm))
399  mcols_ptr(1:nm+1) = 0
400  do k = 1, n
401  m = mid(superof(k))
402  mcols_ptr(m+1) = mcols_ptr(m+1) + 1
403  enddo
404  mcols_ptr(1) = 1
405  do m = 1, nm
406  mcols_ptr(m+1) = mcols_ptr(m) + mcols_ptr(m+1)
407  enddo
408  do k = 1, n
409  m = mid(superof(k))
410  mcols(mcols_ptr(m)) = k
411  mcols_ptr(m) = mcols_ptr(m) + 1
412  enddo
413  do m = nm, 2, -1
414  mcols_ptr(m) = mcols_ptr(m-1)
415  enddo
416  mcols_ptr(1) = 1
417  do s = 1, nfund
418  if (rep(s) /= s) cycle
419  if (fparent(s) == 0) then
420  mparent(mid(s)) = 0
421  else
422  mparent(mid(s)) = mid(fparent(s))
423  endif
424  enddo
425  call mf_postorder(nm, mparent, morder)
426 
427  nsuper = nm
428  allocate(sptr(nsuper+1), sparent(nsuper), newid(nm))
429  do m = 1, nm
430  newid(morder(m)) = m
431  enddo
432  l = 0
433  sptr(1) = 1
434  do m = 1, nm
435  c = morder(m)
436  do k = mcols_ptr(c), mcols_ptr(c+1)-1
437  l = l + 1
438  post(l) = mcols(k)
439  enddo
440  sptr(m+1) = l + 1
441  if (mparent(c) == 0) then
442  sparent(m) = 0
443  else
444  sparent(m) = newid(mparent(c))
445  endif
446  enddo
447  deallocate(nchild, superof, fptr, fparent, rep, size, mid, mcols_ptr, mcols, mparent, morder, newid)
448  end subroutine mf_supernodes
449 
452  subroutine mf_rowstruct(graph, sym)
453  implicit none
454  type(hecmwst_mf_graph), intent(in) :: graph
455  type(hecmwst_mf_symbolic), intent(inout) :: sym
456  integer(kind=kint), allocatable :: mark(:), head(:), next(:), buf(:), pos(:)
457  integer(kind=kint) :: n, ns, s, c, k, fc, lc, p, i, cnt, cap, l, ncol
458 
459  n = sym%nnode
460  ns = sym%nsuper
461  allocate(mark(n), head(ns), next(ns), buf(n), pos(n))
462  allocate(sym%rptr(ns+1), sym%cmap_ptr(ns+1))
463  mark(1:n) = 0
464  head(1:ns) = 0
465  do s = ns, 1, -1
466  p = sym%sparent(s)
467  if (p == 0) cycle
468  next(s) = head(p)
469  head(p) = s
470  enddo
471  cap = 0
472  do k = 1, n
473  cap = cap + sym%colcnt(k)
474  enddo
475  allocate(sym%rlist(cap))
476  sym%rptr(1) = 1
477  do s = 1, ns
478  fc = sym%sptr(s)
479  lc = sym%sptr(s+1) - 1
480  cnt = 0
481  do k = fc, lc
482  cnt = cnt + 1
483  buf(cnt) = k
484  mark(k) = s
485  enddo
486  do k = fc, lc
487  do p = graph%xadj(sym%perm(k)), graph%xadj(sym%perm(k)+1)-1
488  i = sym%invp(graph%adjncy(p))
489  if (i <= lc) cycle
490  if (mark(i) == s) cycle
491  mark(i) = s
492  cnt = cnt + 1
493  buf(cnt) = i
494  enddo
495  enddo
496  c = head(s)
497  do while (c /= 0)
498  ncol = sym%sptr(c+1) - sym%sptr(c)
499  do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
500  i = sym%rlist(l)
501  if (i <= lc) cycle
502  if (mark(i) == s) cycle
503  mark(i) = s
504  cnt = cnt + 1
505  buf(cnt) = i
506  enddo
507  c = next(c)
508  enddo
509  call mf_sort(buf(lc-fc+2:cnt), cnt-(lc-fc+1))
510  if (sym%rptr(s) + cnt - 1 > cap) then
511  cap = max(2*cap, sym%rptr(s) + cnt - 1)
512  call mf_grow(sym%rlist, cap)
513  endif
514  sym%rlist(sym%rptr(s):sym%rptr(s)+cnt-1) = buf(1:cnt)
515  sym%rptr(s+1) = sym%rptr(s) + cnt
516  enddo
517 
518  sym%cmap_ptr(1) = 1
519  do c = 1, ns
520  ncol = sym%sptr(c+1) - sym%sptr(c)
521  sym%cmap_ptr(c+1) = sym%cmap_ptr(c) + (sym%rptr(c+1) - sym%rptr(c) - ncol)
522  enddo
523  allocate(sym%cmap(sym%cmap_ptr(ns+1)-1))
524  do s = 1, ns
525  if (head(s) == 0) cycle
526  do l = sym%rptr(s), sym%rptr(s+1) - 1
527  pos(sym%rlist(l)) = l - sym%rptr(s) + 1
528  enddo
529  c = head(s)
530  do while (c /= 0)
531  ncol = sym%sptr(c+1) - sym%sptr(c)
532  k = sym%cmap_ptr(c)
533  do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
534  sym%cmap(k) = pos(sym%rlist(l))
535  k = k + 1
536  enddo
537  c = next(c)
538  enddo
539  enddo
540  deallocate(mark, head, next, buf, pos)
541  end subroutine mf_rowstruct
542 
543  subroutine mf_grow(a, cap)
544  implicit none
545  integer(kind=kint), allocatable, intent(inout) :: a(:)
546  integer(kind=kint), intent(in) :: cap
547  integer(kind=kint), allocatable :: tmp(:)
548 
549  allocate(tmp(cap))
550  tmp(1:size(a)) = a(1:size(a))
551  call move_alloc(tmp, a)
552  end subroutine mf_grow
553 
555  subroutine mf_sort(a, m)
556  implicit none
557  integer(kind=kint), intent(inout) :: a(:)
558  integer(kind=kint), intent(in) :: m
559  integer(kind=kint) :: i, j, c, t
560 
561  do i = m/2, 1, -1
562  j = i
563  t = a(j)
564  do
565  c = 2*j
566  if (c > m) exit
567  if (c < m) then
568  if (a(c+1) > a(c)) c = c + 1
569  endif
570  if (a(c) <= t) exit
571  a(j) = a(c)
572  j = c
573  enddo
574  a(j) = t
575  enddo
576  do i = m, 2, -1
577  t = a(i)
578  a(i) = a(1)
579  j = 1
580  do
581  c = 2*j
582  if (c > i-1) exit
583  if (c < i-1) then
584  if (a(c+1) > a(c)) c = c + 1
585  endif
586  if (a(c) <= t) exit
587  a(j) = a(c)
588  j = c
589  enddo
590  a(j) = t
591  enddo
592  end subroutine mf_sort
593 
597  subroutine mf_estimate(sym)
598  implicit none
599  type(hecmwst_mf_symbolic), intent(inout) :: sym
600  integer(kind=kint) :: s, l, k
601  integer(kind=8) :: nrow, ncol, a, b
602 
603  sym%factor_nnz = 0
604  sym%flops = 0
605  sym%max_front = 0
606  do s = 1, sym%nsuper
607  ncol = 0
608  do k = sym%sptr(s), sym%sptr(s+1) - 1
609  ncol = ncol + sym%ndof(k)
610  enddo
611  nrow = 0
612  do l = sym%rptr(s), sym%rptr(s+1) - 1
613  nrow = nrow + sym%ndof(sym%rlist(l))
614  enddo
615  sym%max_front = max(sym%max_front, int(nrow, kind=kint))
616  sym%factor_nnz = sym%factor_nnz + ncol*nrow - ncol*(ncol-1)/2
617  a = nrow
618  b = nrow - ncol
619  sym%flops = sym%flops + (a*(a+1)*(2*a+1) - b*(b+1)*(2*b+1))/6
620  enddo
621  end subroutine mf_estimate
622 
625  subroutine hecmw_mf_symbolic_check(graph, sym, nerr)
626  implicit none
627  type(hecmwst_mf_graph), intent(in) :: graph
628  type(hecmwst_mf_symbolic), intent(in) :: sym
629  integer(kind=kint), intent(out) :: nerr
630  integer(kind=kint), allocatable :: fdesc(:), dsize(:), superof(:), mark(:)
631  integer(kind=kint) :: n, ns, k, s, p, c, l, i, fc, lc, ncol, nbad
632  integer(kind=8) :: nnz_node, nnz_cnt
633  type(hecmwst_mf_symbolic) :: tmp
634 
635  nerr = 0
636  n = sym%nnode
637  ns = sym%nsuper
638  allocate(fdesc(n), dsize(n), superof(n), mark(n))
639 
640  nbad = 0
641  do k = 1, n
642  if (sym%perm(k) < 1 .or. sym%perm(k) > n) then
643  nbad = nbad + 1
644  else if (sym%invp(sym%perm(k)) /= k) then
645  nbad = nbad + 1
646  endif
647  enddo
648  if (nbad > 0) then
649  nerr = nerr + 1
650  write(*,'(a,i0)') '[DIRECTmf] check: perm/invp are not inverse, violations = ', nbad
651  endif
652 
653  nbad = 0
654  do k = 1, n
655  fdesc(k) = k
656  dsize(k) = 0
657  enddo
658  do k = 1, n
659  p = sym%parent(k)
660  if (p == 0) cycle
661  if (p <= k .or. p > n) then
662  nbad = nbad + 1
663  cycle
664  endif
665  fdesc(p) = min(fdesc(p), fdesc(k))
666  dsize(p) = dsize(p) + (k - fdesc(k) + 1)
667  enddo
668  if (sym%nmerge == 0) then
669  do k = 1, n
670  if (dsize(k) /= k - fdesc(k)) nbad = nbad + 1
671  enddo
672  endif
673  if (nbad > 0) then
674  nerr = nerr + 1
675  write(*,'(a,i0)') '[DIRECTmf] check: parent is not a topologically ordered tree, violations = ', nbad
676  endif
677 
678  nbad = 0
679  if (sym%sptr(1) /= 1 .or. sym%sptr(ns+1) /= n+1) nbad = nbad + 1
680  do s = 1, ns
681  if (sym%sptr(s+1) <= sym%sptr(s)) nbad = nbad + 1
682  enddo
683  if (nbad > 0) then
684  nerr = nerr + 1
685  write(*,'(a)') '[DIRECTmf] check: sptr does not partition the columns'
686  deallocate(fdesc, dsize, superof, mark)
687  return
688  endif
689  do s = 1, ns
690  superof(sym%sptr(s):sym%sptr(s+1)-1) = s
691  enddo
692  do s = 1, ns
693  lc = sym%sptr(s+1) - 1
694  do k = sym%sptr(s), lc - 1
695  if (sym%parent(k) == 0) then
696  nbad = nbad + 1
697  else if (superof(sym%parent(k)) /= s) then
698  nbad = nbad + 1
699  endif
700  enddo
701  if (sym%parent(lc) == 0) then
702  if (sym%sparent(s) /= 0) nbad = nbad + 1
703  else
704  if (sym%sparent(s) /= superof(sym%parent(lc))) nbad = nbad + 1
705  if (sym%sparent(s) <= s) nbad = nbad + 1
706  endif
707  enddo
708  if (nbad > 0) then
709  nerr = nerr + 1
710  write(*,'(a,i0)') '[DIRECTmf] check: supernodes inconsistent with the elimination tree, violations = ', nbad
711  endif
712 
713  nbad = 0
714  do s = 1, ns
715  fc = sym%sptr(s)
716  lc = sym%sptr(s+1) - 1
717  ncol = lc - fc + 1
718  if (sym%rptr(s+1) - sym%rptr(s) < ncol) then
719  nbad = nbad + 1
720  cycle
721  endif
722  do l = sym%rptr(s), sym%rptr(s+1) - 1
723  i = sym%rlist(l)
724  if (l - sym%rptr(s) < ncol) then
725  if (i /= fc + (l - sym%rptr(s))) nbad = nbad + 1
726  else
727  if (i <= lc .or. i > n) nbad = nbad + 1
728  if (l > sym%rptr(s)) then
729  if (i <= sym%rlist(l-1)) nbad = nbad + 1
730  endif
731  endif
732  enddo
733  enddo
734  if (nbad > 0) then
735  nerr = nerr + 1
736  write(*,'(a,i0)') '[DIRECTmf] check: rlist not ascending or not led by the own columns, violations = ', nbad
737  endif
738 
739  ! every entry of A below the diagonal lies in the structure of L
740  nbad = 0
741  mark(1:n) = 0
742  do s = 1, ns
743  do l = sym%rptr(s), sym%rptr(s+1) - 1
744  mark(sym%rlist(l)) = s
745  enddo
746  do k = sym%sptr(s), sym%sptr(s+1) - 1
747  do p = graph%xadj(sym%perm(k)), graph%xadj(sym%perm(k)+1)-1
748  i = sym%invp(graph%adjncy(p))
749  if (i > k .and. mark(i) /= s) nbad = nbad + 1
750  enddo
751  enddo
752  enddo
753  if (nbad > 0) then
754  nerr = nerr + 1
755  write(*,'(a,i0)') '[DIRECTmf] check: graph edges missing from rlist, violations = ', nbad
756  endif
757 
758  ! colcnt(k) equals the rows of the supernode from k down when no relaxation was applied
759  nbad = 0
760  nnz_node = 0
761  nnz_cnt = 0
762  do s = 1, ns
763  fc = sym%sptr(s)
764  lc = sym%sptr(s+1) - 1
765  do k = fc, lc
766  c = (sym%rptr(s+1) - sym%rptr(s)) - (k - fc)
767  nnz_node = nnz_node + c
768  nnz_cnt = nnz_cnt + sym%colcnt(k)
769  if (sym%colcnt(k) > c) nbad = nbad + 1
770  if (sym%nmerge == 0 .and. sym%colcnt(k) /= c) nbad = nbad + 1
771  enddo
772  enddo
773  if (nbad > 0) then
774  nerr = nerr + 1
775  write(*,'(a,i0)') '[DIRECTmf] check: colcnt inconsistent with rlist, violations = ', nbad
776  endif
777  if (nnz_cnt > nnz_node .or. (sym%nmerge == 0 .and. nnz_cnt /= nnz_node)) then
778  nerr = nerr + 1
779  write(*,'(a,i0,a,i0)') '[DIRECTmf] check: sum(colcnt) = ', nnz_cnt, ' vs rlist node entries = ', nnz_node
780  endif
781 
782  nbad = 0
783  do c = 1, ns
784  p = sym%sparent(c)
785  ncol = sym%sptr(c+1) - sym%sptr(c)
786  if (sym%cmap_ptr(c+1) - sym%cmap_ptr(c) /= sym%rptr(c+1) - sym%rptr(c) - ncol) then
787  nbad = nbad + 1
788  cycle
789  endif
790  if (p == 0) cycle
791  k = sym%cmap_ptr(c)
792  do l = sym%rptr(c) + ncol, sym%rptr(c+1) - 1
793  i = sym%cmap(k)
794  if (i < 1 .or. i > sym%rptr(p+1) - sym%rptr(p)) then
795  nbad = nbad + 1
796  else if (sym%rlist(sym%rptr(p) + i - 1) /= sym%rlist(l)) then
797  nbad = nbad + 1
798  endif
799  k = k + 1
800  enddo
801  enddo
802  if (nbad > 0) then
803  nerr = nerr + 1
804  write(*,'(a,i0)') '[DIRECTmf] check: cmap does not map onto the parent rlist, violations = ', nbad
805  endif
806 
807  tmp%nnode = n
808  tmp%nsuper = ns
809  allocate(tmp%ndof(n), tmp%sptr(ns+1), tmp%rptr(ns+1), tmp%rlist(sym%rptr(ns+1)-1))
810  tmp%ndof(1:n) = sym%ndof(1:n)
811  tmp%sptr(1:ns+1) = sym%sptr(1:ns+1)
812  tmp%rptr(1:ns+1) = sym%rptr(1:ns+1)
813  tmp%rlist(1:sym%rptr(ns+1)-1) = sym%rlist(1:sym%rptr(ns+1)-1)
814  call mf_estimate(tmp)
815  if (tmp%factor_nnz /= sym%factor_nnz .or. tmp%flops /= sym%flops .or. tmp%max_front /= sym%max_front) then
816  nerr = nerr + 1
817  write(*,'(a)') '[DIRECTmf] check: stored estimates differ from recomputation'
818  endif
820  deallocate(fdesc, dsize, superof, mark)
821  end subroutine hecmw_mf_symbolic_check
822 
823  subroutine hecmw_mf_symbolic_print(sym)
824  implicit none
825  type(hecmwst_mf_symbolic), intent(in) :: sym
826  integer(kind=kint) :: k, ndof_min, ndof_max
827  integer(kind=8) :: ndof_tot
828 
829  ndof_tot = 0
830  ndof_min = huge(1_kint)
831  ndof_max = 0
832  do k = 1, sym%nnode
833  ndof_tot = ndof_tot + sym%ndof(k)
834  ndof_min = min(ndof_min, sym%ndof(k))
835  ndof_max = max(ndof_max, sym%ndof(k))
836  enddo
837  write(*,'(a,i0,a,i0,a,i0,a,i0,a)') '[DIRECTmf]: nodes = ', sym%nnode, ', dofs = ', ndof_tot, &
838  ' (ndof ', ndof_min, '..', ndof_max, ')'
839  write(*,'(a,i0,a,i0,a,i0)') '[DIRECTmf]: supernodes = ', sym%nsuper, ', relaxed merges = ', sym%nmerge, &
840  ', max front (dof) = ', sym%max_front
841  write(*,'(a,i0,a,f10.3,a)') '[DIRECTmf]: factor nnz (dof) = ', sym%factor_nnz, &
842  ' (', real(sym%factor_nnz, kind=kreal)*8.0d0/1024.0d0**3, ' GB)'
843  write(*,'(a,i0,a,f12.3,a)') '[DIRECTmf]: factorization flops = ', sym%flops, &
844  ' (', real(sym%flops, kind=kreal)/1.0d9, ' GFLOP)'
845  end subroutine hecmw_mf_symbolic_print
846 
853  subroutine hecmw_mf_symbolic_cluster(graph, sym, perm)
854  implicit none
855  type(hecmwst_mf_graph), intent(in) :: graph
856  type(hecmwst_mf_symbolic), intent(in) :: sym
857  integer(kind=kint), intent(out) :: perm(:)
858  integer(kind=kint), allocatable :: own(:), deg(:), queue(:)
859  integer(kind=kint) :: s, k, i, j, p, pos, head, tail, seed, mindeg
860 
861  allocate(own(graph%nnode), deg(graph%nnode), queue(graph%nnode))
862  do s = 1, sym%nsuper
863  do k = sym%sptr(s), sym%sptr(s+1) - 1
864  own(sym%perm(k)) = s
865  enddo
866  enddo
867  pos = 0
868  do s = 1, sym%nsuper
869  do k = sym%sptr(s), sym%sptr(s+1) - 1
870  i = sym%perm(k)
871  deg(i) = 0
872  do p = graph%xadj(i), graph%xadj(i+1) - 1
873  if (own(graph%adjncy(p)) == s) deg(i) = deg(i) + 1
874  enddo
875  enddo
876  do
877  seed = 0
878  mindeg = huge(seed)
879  do k = sym%sptr(s), sym%sptr(s+1) - 1
880  i = sym%perm(k)
881  if (own(i) == s .and. deg(i) < mindeg) then
882  mindeg = deg(i)
883  seed = i
884  endif
885  enddo
886  if (seed == 0) exit
887  own(seed) = -s
888  queue(1) = seed
889  head = 1
890  tail = 1
891  do while (head <= tail)
892  i = queue(head)
893  head = head + 1
894  pos = pos + 1
895  perm(pos) = i
896  do p = graph%xadj(i), graph%xadj(i+1) - 1
897  j = graph%adjncy(p)
898  if (own(j) == s) then
899  own(j) = -s
900  tail = tail + 1
901  queue(tail) = j
902  endif
903  enddo
904  enddo
905  enddo
906  enddo
907  deallocate(own, deg, queue)
908  end subroutine hecmw_mf_symbolic_cluster
909 
910 end module hecmw_mf_symbolic
Compressed (node level) graph of a block sparse matrix for the multifrontal solver.
Symbolic factorization (elimination tree, column counts, supernodes, row structure) for the multifron...
subroutine, public hecmw_mf_symbolic_cluster(graph, sym, perm)
Refined permutation for the BLR compression: the own nodes of every supernode are reordered by a BFS ...
subroutine, public hecmw_mf_symbolic_finalize(sym)
subroutine, public hecmw_mf_symbolic_print(sym)
subroutine, public hecmw_mf_symbolic_build(graph, perm, relax_nodes, sym)
perm(k) is the original node placed at position k by a fill reducing ordering; any topological reorde...
subroutine, public hecmw_mf_symbolic_check(graph, sym, nerr)
Consistency checks of a built structure against its graph; every violation is reported on unit 6 and ...
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=4), parameter kint
integer(kind=4), parameter kreal