FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
hecmw_solver_direct_mf.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 !-------------------------------------------------------------------------------
11  use hecmw_util
12  use m_hecmw_comm_f
14  use hecmw_ordering
15  use hecmw_mf_graph
17  use hecmw_mf_dist
19  use hecmw_mf_kernel
23  !$ use omp_lib
24  implicit none
25 
26  private
27  public :: hecmw_solve_direct_mf
28  public :: hecmw_mf_compare_builtin
29 
31  integer(kind=kint), parameter :: MF_RELAX_COLS = 16
33  integer(kind=kint), parameter :: MF_TILE = 256
35  integer(kind=kint), parameter :: MF_IR_STEPS = 5
37  real(kind=kreal), parameter :: mf_ir_tol = 1.0d-8
38 
39  type(hecmwST_mf_symbolic), save :: SYM
40  type(hecmwST_mf_factor), save :: FCT
41  type(hecmwST_mf_map), save :: MAP
42  type(hecmwST_mf_gmat), save :: GMAT
43 
44 contains
45 
46  subroutine hecmw_solve_direct_mf(hecMESH, hecMAT, imsg)
47  implicit none
48  type(hecmwst_local_mesh), intent(inout) :: hecmesh
49  type(hecmwst_matrix), intent(inout) :: hecmat
50  integer(kind=kint), intent(in) :: imsg
51  type(hecmwst_mf_graph) :: graph
52  integer(kind=kint), allocatable :: perm(:), invp(:)
53  integer(kind=kint) :: loglevel, iterlog, timelog, ordering, n, nerr, relax, tile, ierr, idof, node, nthreads, irmax, it, eta
54  real(kind=kreal) :: t1, t2, irtol, bnrm, rnrm, rprev, tcomm
55  real(kind=kreal), allocatable :: rr(:), dd(:), xp(:)
56  logical :: clustered
57 
58  ! TIMELOG holds the stage times, ITERLOG the refinement residuals, LOGLEVEL the
59  ! diagnostics; an unset LOGLEVEL (-1) means no diagnostics here, with no fallback
60  ! to the other two flags
61  loglevel = hecmw_mat_get_loglevel(hecmat)
62  if (loglevel < 0) loglevel = 0
63  iterlog = hecmw_mat_get_iterlog(hecmat)
64  timelog = hecmw_mat_get_timelog(hecmat)
65  if (hecmw_comm_get_rank() /= 0) then
66  loglevel = 0
67  iterlog = 0
68  timelog = 0
69  endif
70 
71  if (hecmesh%PETOT > 1) then
72  call hecmw_solve_direct_mf_dist(hecmesh, hecmat, imsg, loglevel, iterlog, timelog)
73  return
74  endif
75 
76  if (hecmat%Iarray(98) == 1) then
77  t1 = hecmw_wtime()
78  call hecmw_mf_graph_from_hecmat(hecmat, graph)
79  n = graph%nnode
80  allocate(perm(n), invp(n))
81  ordering = hecmat%Iarray(41)
82  call hecmw_ordering_gen(n, n + (graph%xadj(n+1)-1)/2, graph%xadj, graph%adjncy, perm, invp, ordering, loglevel)
83  relax = hecmat%Iarray(46)
84  if (relax <= 0) relax = mf_relax_cols
85  relax = max(1, relax / hecmat%NDOF)
87  call hecmw_mf_symbolic_build(graph, perm, relax, sym)
88  clustered = hecmat%Iarray(43) /= 0 .and. hecmw_mf_kernel_blr_available()
89  if (clustered) then
90  call hecmw_mf_symbolic_cluster(graph, sym, perm)
92  call hecmw_mf_symbolic_build(graph, perm, relax, sym)
93  endif
94  tile = hecmat%Iarray(45)
95  if (tile <= 0) tile = mf_tile
96  eta = hecmat%Iarray(47)
97  if (eta == 0) eta = mf_blr_eta
98  if (eta < 0) eta = 0
100  call hecmw_mf_numeric_init(graph, sym, tile, clustered, eta, fct)
101  t2 = hecmw_wtime()
102  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: symbolic fct done (', t2 - t1, ' sec)'
103  if (loglevel > 0) then
104  if (clustered) write(*,'(a)') '[DIRECTmf]: separator nodes clustered for BLR'
105  call hecmw_mf_symbolic_print(sym)
106  call hecmw_mf_numeric_print(fct)
107  endif
108  if (loglevel > 1) then
109  call hecmw_mf_symbolic_check(graph, sym, nerr)
110  write(*,'(a,i0)') '[DIRECTmf]: self check violations = ', nerr
111  if (.not. clustered) then
112  call hecmw_mf_compare_builtin(hecmesh, hecmat, graph, ordering, nerr)
113  write(*,'(a,i0)') '[DIRECTmf]: mismatches against built-in DIRECT = ', nerr
114  endif
115  endif
116  deallocate(perm, invp)
117  call hecmw_mf_graph_finalize(graph)
118  endif
119 
120  hecmat%Iarray(98) = 0
121 
122  if (hecmat%Iarray(97) == 1) then
123  fct%mode = hecmat%Iarray(42)
124  if (fct%mode < 0 .or. fct%mode > 2) then
125  if (hecmw_comm_get_rank() == 0) write(*,'(a,i0,a)') &
126  '[DIRECTmf]: WARNING: MF_Mode ', fct%mode, ' is outside 0-2; using the automatic mode'
127  fct%mode = 0
128  endif
129  fct%scan = loglevel > 1
130  fct%blr = hecmat%Iarray(43) /= 0
131  fct%eps = hecmat%Rarray(41)
132  fct%pivot_u = hecmat%Rarray(43)
133  ! threshold partial pivoting is defined for u in (0, 0.5]
134  if (fct%pivot_u > 0.5d0) then
135  if (hecmw_comm_get_rank() == 0) write(*,'(a,1pe9.2,a)') &
136  '[DIRECTmf]: WARNING: MF_PivotThreshold ', fct%pivot_u, ' is above 0.5; using 0.5'
137  fct%pivot_u = 0.5d0
138  endif
139  fct%pivot_zero = hecmat%Rarray(44)
140  fct%blr_beta = hecmat%Rarray(45)
141  if (fct%blr_beta <= 0.0d0) fct%blr_beta = 1.0d0
142  fct%blr_reuse = hecmat%Iarray(48) /= 0
143  if (fct%blr .and. .not. hecmw_mf_kernel_blr_available()) then
144  fct%blr = .false.
145  ! the user asked for BLR, so the fallback is reported regardless of LOGLEVEL
146  if (hecmw_comm_get_rank() == 0) write(*,'(a)') '[DIRECTmf]: BLR disabled (built without LAPACK)'
147  endif
148  t1 = hecmw_wtime()
149  call hecmw_mf_numeric_factor(hecmat, sym, fct, ierr)
150  t2 = hecmw_wtime()
151  if (ierr /= 0) then
152  if (ierr > 0) then
153  idof = fct%pdof(ierr)
154  ! the node prints as the user's id where the matrix rows are the mesh nodes
155  ! (not the expanded saddle-point or coarse-grid systems)
156  node = (idof-1)/hecmat%NDOF + 1
157  if (hecmat%NP == hecmesh%n_node) node = hecmesh%global_node_ID(node)
158  write(imsg,'(a,i0,a,i0,a)') 'ERROR: DIRECTmf: no acceptable pivot at node ', node, &
159  ' dof ', mod(idof-1, hecmat%NDOF) + 1, ' (the matrix may be singular)'
160  write(*,'(a,i0,a,i0,a)') 'ERROR: DIRECTmf: no acceptable pivot at node ', node, &
161  ' dof ', mod(idof-1, hecmat%NDOF) + 1, ' (the matrix may be singular)'
162  else if (ierr == -1) then
163  write(imsg,*) 'ERROR: DIRECTmf: block size of the matrix does not match the symbolic structure'
164  write(*,*) 'ERROR: DIRECTmf: block size of the matrix does not match the symbolic structure'
165  else
166  write(imsg,*) 'ERROR: DIRECTmf: the nonzero structure of the matrix is not symmetric'
167  write(*,*) 'ERROR: DIRECTmf: the nonzero structure of the matrix is not symmetric'
168  endif
170  endif
171  hecmat%Iarray(97) = 0
172  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: numeric fct done (', t2 - t1, ' sec)'
173  if (loglevel > 0) then
174  nthreads = 1
175  !$ nthreads = omp_get_max_threads()
176  write(*,'(a,i0)') '[DIRECTmf]: threads = ', nthreads
177  write(*,'(a,1pe9.2,a,1pe9.2)') '[DIRECTmf]: options: pivot u = ', fct%pivot_u, &
178  ', zero pivot factor = ', fct%pivot_zero
179  if (fct%lu) then
180  if (fct%mode == 2) then
181  write(*,'(a)') '[DIRECTmf]: mode = LU (forced by option)'
182  else
183  write(*,'(a)') '[DIRECTmf]: mode = LU (unsymmetric matrix)'
184  endif
185  if (loglevel > 1) write(*,'(a,1pe9.2)') '[DIRECTmf]: asymmetry = ', fct%asym
186  write(*,'(a,i0,a,i0,a,i0,a)') '[DIRECTmf]: row swaps = ', fct%n_swap, ', delayed = ', fct%n_delay, &
187  ' (max front growth = ', fct%max_growth, ' dofs)'
188  else
189  if (fct%mode == 1) then
190  write(*,'(a)') '[DIRECTmf]: mode = LDLt (forced by option)'
191  else
192  write(*,'(a)') '[DIRECTmf]: mode = LDLt'
193  endif
194  if (loglevel > 1) write(*,'(a,1pe9.2)') '[DIRECTmf]: asymmetry = ', fct%asym
195  write(*,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') '[DIRECTmf]: inertia (+,-) = (', fct%n_pos, ',', fct%n_neg, &
196  '), 2x2 pivots = ', fct%n_2x2, ', swaps = ', fct%n_swap, ', delayed = ', fct%n_delay, &
197  ' (max front growth = ', fct%max_growth, ' dofs)'
198  endif
199  write(*,'(a,i0,a,f10.3,a,i0,a,i0)') '[DIRECTmf]: factor words = ', fct%factor_words_act, ' (', &
200  real(fct%factor_words_act, kind=kreal)*8.0d0/1024.0d0**3, ' GB), stack peak words = ', fct%stack_peak_act, &
201  ', front words = ', fct%front_words_act
202  if (fct%blr) then
203  write(*,'(a,1pe9.2,a,i0,a,0pf6.1,a)') '[DIRECTmf]: BLR: eps = ', fct%eps, &
204  ', factor words full rank = ', fct%blr_words_fr, ' (', &
205  100.0d0*(1.0d0 - real(fct%factor_words_act, kind=kreal)/max(real(fct%blr_words_fr, kind=kreal), 1.0d0)), &
206  '% saved)'
207  write(*,'(a,i0,a,f5.2,a,l1)') '[DIRECTmf]: BLR: skip eta = ', fct%blr_eta, &
208  ', gain cap beta = ', fct%blr_beta, ', rank reuse = ', fct%blr_reuse
209  write(*,'(a,i0,a,i0,a,i0,a,i0,a,f8.1)') '[DIRECTmf]: BLR: tiles compressed = ', fct%blr_tiles_lr, ' of ', &
210  fct%blr_tiles, ', skipped = ', fct%blr_tiles_skip, ', rank max = ', fct%blr_rank_max, ', rank avg = ', &
211  real(fct%blr_rank_sum, kind=kreal)/max(real(fct%blr_tiles_lr, kind=kreal), 1.0d0)
212  endif
213  write(*,'(a,i0,a,f10.3,a)') '[DIRECTmf]: front words held concurrently (peak) = ', fct%front_peak, ' (', &
214  real(fct%front_peak, kind=kreal)*8.0d0/1024.0d0**3, ' GB)'
215  endif
216  endif
217 
218  if (.not. fct%factored) then
219  write(imsg,*) 'ERROR: DIRECTmf: numeric factorization not performed'
220  write(*,*) 'ERROR: DIRECTmf: numeric factorization not performed'
222  endif
223  t1 = hecmw_wtime()
224  call hecmw_mf_numeric_solve(sym, fct, hecmat%B, hecmat%X)
225  t2 = hecmw_wtime()
226  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: solve done (', t2 - t1, ' sec)'
227 
228  irmax = hecmat%Iarray(44)
229  if (fct%blr .and. irmax == 0) irmax = mf_ir_steps
230  if (irmax > 0) then
231  irtol = hecmat%Rarray(42)
232  if (.not. (irtol > 0.0d0)) irtol = mf_ir_tol
233  n = hecmat%NP * hecmat%NDOF
234  allocate(rr(n), dd(n), xp(n))
235  tcomm = 0.0d0
236  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, hecmat%B, bnrm, tcomm)
237  t1 = hecmw_wtime()
238  rprev = huge(rprev)
239  do it = 1, irmax
240  call hecmw_matresid(hecmesh, hecmat, hecmat%X, hecmat%B, rr, tcomm)
241  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, rr, rr, rnrm, tcomm)
242  rnrm = sqrt(rnrm / max(bnrm, tiny(bnrm)))
243  if (iterlog > 0) write(*,'(a,i0,a,1pe11.4)') '[DIRECTmf]: refinement ', it - 1, ': residual = ', rnrm
244  if (rnrm <= irtol) exit
245  ! a step that grew the residual would hand back a worse solution than it got,
246  ! so the step is undone and the sweep stops with a warning
247  if (rnrm > rprev) then
248  hecmat%X(1:n) = xp(1:n)
249  if (hecmw_comm_get_rank() == 0) write(*,'(a,1pe11.4)') &
250  '[DIRECTmf]: WARNING: refinement diverged, reverted to residual = ', rprev
251  exit
252  endif
253  rprev = rnrm
254  xp(1:n) = hecmat%X(1:n)
255  call hecmw_mf_numeric_solve(sym, fct, rr, dd)
256  hecmat%X(1:n) = hecmat%X(1:n) + dd(1:n)
257  enddo
258  t2 = hecmw_wtime()
259  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: refinement done (', t2 - t1, ' sec)'
260  deallocate(rr, dd, xp)
261  else if (irmax == 0 .and. iterlog > 0) then
262  ! a negative irmax asks for no residual work at all (the contact wrapper measures
263  ! its saddle-point system itself and disables this path with -1)
264  n = hecmat%NP * hecmat%NDOF
265  allocate(rr(n))
266  tcomm = 0.0d0
267  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, hecmat%B, bnrm, tcomm)
268  call hecmw_matresid(hecmesh, hecmat, hecmat%X, hecmat%B, rr, tcomm)
269  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, rr, rr, rnrm, tcomm)
270  rnrm = sqrt(rnrm / max(bnrm, tiny(bnrm)))
271  write(*,'(a,1pe11.4)') '[DIRECTmf]: residual = ', rnrm
272  deallocate(rr)
273  endif
274  end subroutine hecmw_solve_direct_mf
275 
284  subroutine hecmw_solve_direct_mf_dist(hecMESH, hecMAT, imsg, loglevel, iterlog, timelog)
285  implicit none
286  type(hecmwst_local_mesh), intent(inout) :: hecmesh
287  type(hecmwst_matrix), intent(inout) :: hecmat
288  integer(kind=kint), intent(in) :: imsg, loglevel, iterlog, timelog
289  type(hecmwst_mf_graph) :: graph
290  integer(kind=kint), allocatable :: perm(:), invp(:)
291  real(kind=kreal), allocatable :: gb(:), gx(:), rr(:), wpr(:), wmr(:), xp(:)
292  integer(kind=kint) :: ordering, n, nerr, relax, tile, ierr, idof, nthreads, irmax, it, i, ofs, eta, gnode, d
293  integer(kind=8) :: wrepl
294  real(kind=kreal) :: t1, t2, irtol, bnrm, rnrm, rprev, tcomm
295  logical :: clustered
296 
297  clustered = .false.
298  if (hecmat%Iarray(98) == 1) then
299  t1 = hecmw_wtime()
300  call hecmw_mf_dist_gmat_build(hecmesh, hecmat, gmat)
302  relax = hecmat%Iarray(46)
303  if (relax <= 0) relax = mf_relax_cols
304  relax = max(1, relax / hecmat%NDOF)
305  clustered = hecmat%Iarray(43) /= 0 .and. hecmw_mf_kernel_blr_available()
306  if (hecmw_comm_get_rank() == 0) then
307  call hecmw_mf_graph_from_hecmat(gmat%mat, graph)
308  n = graph%nnode
309  allocate(perm(n), invp(n))
310  ordering = hecmat%Iarray(41)
311  call hecmw_ordering_gen(n, n + (graph%xadj(n+1)-1)/2, graph%xadj, graph%adjncy, perm, invp, ordering, loglevel)
312  call hecmw_mf_symbolic_build(graph, perm, relax, sym)
313  if (clustered) then
314  call hecmw_mf_symbolic_cluster(graph, sym, perm)
316  call hecmw_mf_symbolic_build(graph, perm, relax, sym)
317  endif
318  if (loglevel > 1) then
319  call hecmw_mf_symbolic_check(graph, sym, nerr)
320  write(*,'(a,i0)') '[DIRECTmf]: self check violations = ', nerr
321  endif
322  deallocate(perm, invp)
323  endif
324  call hecmw_mf_dist_symbolic_bcast(sym, 0)
326  call hecmw_mf_dist_map_build(sym, map)
327  call hecmw_mf_dist_gmat_part(sym, map, gmat)
328  allocate(wmr(map%nprocs))
329  call mf_gather_matwords(gmat, wmr, wrepl)
330  tile = hecmat%Iarray(45)
331  if (tile <= 0) tile = mf_tile
332  eta = hecmat%Iarray(47)
333  if (eta == 0) eta = mf_blr_eta
334  if (eta < 0) eta = 0
335  call hecmw_mf_numeric_finalize(fct)
336  call hecmw_mf_numeric_init(graph, sym, tile, clustered, eta, fct)
337  call hecmw_mf_graph_finalize(graph)
338  if (clustered .and. eta > 0) call hecmw_mf_numeric_admis_bcast(fct, 0)
339  t2 = hecmw_wtime()
340  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: symbolic fct done (', t2 - t1, ' sec)'
341  if (loglevel > 0) then
342  if (clustered) write(*,'(a)') '[DIRECTmf]: separator nodes clustered for BLR'
343  write(*,'(a,i0,a,i0)') '[DIRECTmf]: MPI ranks = ', map%nprocs, ', upper fronts = ', map%nupper
344  write(*,'(a,i0,a,*(i0,1x))') '[DIRECTmf]: matrix words replicated = ', wrepl, ', held per rank = ', &
345  (nint(wmr(i), kind=8), i = 1, map%nprocs)
346  call hecmw_mf_symbolic_print(sym)
347  call hecmw_mf_numeric_print(fct)
348  endif
349  deallocate(wmr)
350  hecmat%Iarray(98) = 0
351  endif
352 
353  if (hecmat%Iarray(97) == 1) then
354  fct%mode = hecmat%Iarray(42)
355  if (fct%mode < 0 .or. fct%mode > 2) then
356  if (hecmw_comm_get_rank() == 0) write(*,'(a,i0,a)') &
357  '[DIRECTmf]: WARNING: MF_Mode ', fct%mode, ' is outside 0-2; using the automatic mode'
358  fct%mode = 0
359  endif
360  fct%scan = loglevel > 1
361  fct%blr = hecmat%Iarray(43) /= 0
362  fct%eps = hecmat%Rarray(41)
363  fct%pivot_u = hecmat%Rarray(43)
364  ! threshold partial pivoting is defined for u in (0, 0.5]
365  if (fct%pivot_u > 0.5d0) then
366  if (hecmw_comm_get_rank() == 0) write(*,'(a,1pe9.2,a)') &
367  '[DIRECTmf]: WARNING: MF_PivotThreshold ', fct%pivot_u, ' is above 0.5; using 0.5'
368  fct%pivot_u = 0.5d0
369  endif
370  fct%pivot_zero = hecmat%Rarray(44)
371  fct%blr_beta = hecmat%Rarray(45)
372  if (fct%blr_beta <= 0.0d0) fct%blr_beta = 1.0d0
373  fct%blr_reuse = hecmat%Iarray(48) /= 0
374  if (fct%blr .and. .not. hecmw_mf_kernel_blr_available()) then
375  fct%blr = .false.
376  ! the user asked for BLR, so the fallback is reported regardless of LOGLEVEL
377  if (hecmw_comm_get_rank() == 0) write(*,'(a)') '[DIRECTmf]: BLR disabled (built without LAPACK)'
378  endif
379  call hecmw_mf_dist_gmat_vals(hecmat, gmat)
380  t1 = hecmw_wtime()
381  call hecmw_mf_numeric_factor_mpi(gmat%mat, sym, map, fct, ierr)
382  t2 = hecmw_wtime()
383  if (ierr /= 0) then
384  if (hecmw_comm_get_rank() == 0) then
385  if (ierr > 0) then
386  idof = fct%pdof(ierr)
387  ! the row is in the gathered numbering; gid maps it back to the user's node id
388  write(imsg,'(a,i0,a,i0,a)') 'ERROR: DIRECTmf: no acceptable pivot at node ', &
389  gmat%gid((idof-1)/hecmat%NDOF + 1), &
390  ' dof ', mod(idof-1, hecmat%NDOF) + 1, ' (the matrix may be singular)'
391  write(*,'(a,i0,a,i0,a)') 'ERROR: DIRECTmf: no acceptable pivot at node ', &
392  gmat%gid((idof-1)/hecmat%NDOF + 1), &
393  ' dof ', mod(idof-1, hecmat%NDOF) + 1, ' (the matrix may be singular)'
394  else if (ierr == -1) then
395  write(imsg,*) 'ERROR: DIRECTmf: block size of the matrix does not match the symbolic structure'
396  write(*,*) 'ERROR: DIRECTmf: block size of the matrix does not match the symbolic structure'
397  else
398  write(imsg,*) 'ERROR: DIRECTmf: the nonzero structure of the matrix is not symmetric'
399  write(*,*) 'ERROR: DIRECTmf: the nonzero structure of the matrix is not symmetric'
400  endif
401  endif
403  endif
404  hecmat%Iarray(97) = 0
405  allocate(wpr(map%nprocs))
406  call mf_reduce_stats(fct, wpr)
407  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: numeric fct done (', t2 - t1, ' sec)'
408  if (loglevel > 0) then
409  nthreads = 1
410  !$ nthreads = omp_get_max_threads()
411  write(*,'(a,i0,a,i0)') '[DIRECTmf]: ranks = ', map%nprocs, ', threads per rank = ', nthreads
412  write(*,'(a,1pe9.2,a,1pe9.2)') '[DIRECTmf]: options: pivot u = ', fct%pivot_u, &
413  ', zero pivot factor = ', fct%pivot_zero
414  if (fct%lu) then
415  if (fct%mode == 2) then
416  write(*,'(a)') '[DIRECTmf]: mode = LU (forced by option)'
417  else
418  write(*,'(a)') '[DIRECTmf]: mode = LU (unsymmetric matrix)'
419  endif
420  if (loglevel > 1) write(*,'(a,1pe9.2)') '[DIRECTmf]: asymmetry = ', fct%asym
421  write(*,'(a,i0,a,i0,a,i0,a)') '[DIRECTmf]: row swaps = ', fct%n_swap, ', delayed = ', fct%n_delay, &
422  ' (max front growth = ', fct%max_growth, ' dofs)'
423  else
424  if (fct%mode == 1) then
425  write(*,'(a)') '[DIRECTmf]: mode = LDLt (forced by option)'
426  else
427  write(*,'(a)') '[DIRECTmf]: mode = LDLt'
428  endif
429  if (loglevel > 1) write(*,'(a,1pe9.2)') '[DIRECTmf]: asymmetry = ', fct%asym
430  write(*,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') '[DIRECTmf]: inertia (+,-) = (', fct%n_pos, ',', fct%n_neg, &
431  '), 2x2 pivots = ', fct%n_2x2, ', swaps = ', fct%n_swap, ', delayed = ', fct%n_delay, &
432  ' (max front growth = ', fct%max_growth, ' dofs)'
433  endif
434  write(*,'(a,i0,a,f10.3,a,i0,a,i0)') '[DIRECTmf]: factor words = ', fct%factor_words_act, ' (', &
435  real(fct%factor_words_act, kind=kreal)*8.0d0/1024.0d0**3, ' GB), stack peak words = ', fct%stack_peak_act, &
436  ', front words = ', fct%front_words_act
437  write(*,'(a,*(i0,1x))') '[DIRECTmf]: factor words per rank = ', (nint(wpr(i), kind=8), i = 1, map%nprocs)
438  if (fct%blr) then
439  write(*,'(a,1pe9.2,a,i0,a,0pf6.1,a)') '[DIRECTmf]: BLR: eps = ', fct%eps, &
440  ', factor words full rank = ', fct%blr_words_fr, ' (', &
441  100.0d0*(1.0d0 - real(fct%factor_words_act, kind=kreal)/max(real(fct%blr_words_fr, kind=kreal), 1.0d0)), &
442  '% saved)'
443  write(*,'(a,i0,a,f5.2,a,l1)') '[DIRECTmf]: BLR: skip eta = ', fct%blr_eta, &
444  ', gain cap beta = ', fct%blr_beta, ', rank reuse = ', fct%blr_reuse
445  write(*,'(a,i0,a,i0,a,i0,a,i0,a,f8.1)') '[DIRECTmf]: BLR: tiles compressed = ', fct%blr_tiles_lr, ' of ', &
446  fct%blr_tiles, ', skipped = ', fct%blr_tiles_skip, ', rank max = ', fct%blr_rank_max, ', rank avg = ', &
447  real(fct%blr_rank_sum, kind=kreal)/max(real(fct%blr_tiles_lr, kind=kreal), 1.0d0)
448  endif
449  write(*,'(a,i0,a,f10.3,a)') '[DIRECTmf]: front words held concurrently (peak) = ', fct%front_peak, ' (', &
450  real(fct%front_peak, kind=kreal)*8.0d0/1024.0d0**3, ' GB)'
451  endif
452  deallocate(wpr)
453  endif
454 
455  if (.not. fct%factored) then
456  if (hecmw_comm_get_rank() == 0) then
457  write(imsg,*) 'ERROR: DIRECTmf: numeric factorization not performed'
458  write(*,*) 'ERROR: DIRECTmf: numeric factorization not performed'
459  endif
461  endif
462  allocate(gb(fct%ndof_tot), gx(fct%ndof_tot))
463  ! the global rows follow the gid numbering; ofs locates my nodes in the gathered order
464  ofs = gmat%ndisp(hecmw_comm_get_rank()+1)
465  call hecmw_mf_dist_gather_vec(gmat, hecmat%B, gb)
466  t1 = hecmw_wtime()
467  call hecmw_mf_numeric_solve_mpi(sym, map, fct, gb, gx)
468  t2 = hecmw_wtime()
469  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: solve done (', t2 - t1, ' sec)'
470  do i = 1, hecmat%N
471  gnode = gmat%g2s(ofs + i)
472  do d = 1, hecmat%NDOF
473  hecmat%X((i-1)*hecmat%NDOF + d) = gx((gnode-1)*hecmat%NDOF + d)
474  enddo
475  enddo
476 
477  irmax = hecmat%Iarray(44)
478  if (fct%blr .and. irmax == 0) irmax = mf_ir_steps
479  if (irmax > 0) then
480  irtol = hecmat%Rarray(42)
481  if (.not. (irtol > 0.0d0)) irtol = mf_ir_tol
482  n = hecmat%NP * hecmat%NDOF
483  allocate(rr(n), xp(hecmat%N * hecmat%NDOF))
484  tcomm = 0.0d0
485  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, hecmat%B, bnrm, tcomm)
486  t1 = hecmw_wtime()
487  rprev = huge(rprev)
488  do it = 1, irmax
489  call hecmw_matresid(hecmesh, hecmat, hecmat%X, hecmat%B, rr, tcomm)
490  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, rr, rr, rnrm, tcomm)
491  rnrm = sqrt(rnrm / max(bnrm, tiny(bnrm)))
492  if (iterlog > 0) write(*,'(a,i0,a,1pe11.4)') '[DIRECTmf]: refinement ', it - 1, ': residual = ', rnrm
493  if (rnrm <= irtol) exit
494  ! a step that grew the residual would hand back a worse solution than it got, so
495  ! the step is undone and the sweep stops (rnrm is collective, every rank agrees)
496  if (rnrm > rprev) then
497  hecmat%X(1:hecmat%N * hecmat%NDOF) = xp(1:hecmat%N * hecmat%NDOF)
498  if (hecmw_comm_get_rank() == 0) write(*,'(a,1pe11.4)') &
499  '[DIRECTmf]: WARNING: refinement diverged, reverted to residual = ', rprev
500  exit
501  endif
502  rprev = rnrm
503  xp(1:hecmat%N * hecmat%NDOF) = hecmat%X(1:hecmat%N * hecmat%NDOF)
504  call hecmw_mf_dist_gather_vec(gmat, rr, gb)
505  call hecmw_mf_numeric_solve_mpi(sym, map, fct, gb, gx)
506  do i = 1, hecmat%N
507  gnode = gmat%g2s(ofs + i)
508  do d = 1, hecmat%NDOF
509  hecmat%X((i-1)*hecmat%NDOF + d) = hecmat%X((i-1)*hecmat%NDOF + d) + gx((gnode-1)*hecmat%NDOF + d)
510  enddo
511  enddo
512  enddo
513  t2 = hecmw_wtime()
514  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: refinement done (', t2 - t1, ' sec)'
515  deallocate(rr, xp)
516  else if (irmax == 0 .and. hecmw_mat_get_iterlog(hecmat) > 0) then
517  ! every rank enters the residual evaluation (it is collective); the passed iterlog
518  ! is zeroed off rank 0 and only gates the print
519  n = hecmat%NP * hecmat%NDOF
520  allocate(rr(n))
521  tcomm = 0.0d0
522  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, hecmat%B, hecmat%B, bnrm, tcomm)
523  call hecmw_matresid(hecmesh, hecmat, hecmat%X, hecmat%B, rr, tcomm)
524  call hecmw_innerproduct_r(hecmesh, hecmat%NDOF, rr, rr, rnrm, tcomm)
525  rnrm = sqrt(rnrm / max(bnrm, tiny(bnrm)))
526  if (iterlog > 0) write(*,'(a,1pe11.4)') '[DIRECTmf]: residual = ', rnrm
527  deallocate(rr)
528  endif
529  call hecmw_update_r(hecmesh, hecmat%X, hecmat%NP, hecmat%NDOF)
530  deallocate(gb, gx)
531  end subroutine hecmw_solve_direct_mf_dist
532 
535  subroutine mf_gather_matwords(gmat, wmr, wrepl)
536  implicit none
537  type(hecmwst_mf_gmat), intent(in) :: gmat
538  real(kind=kreal), intent(out) :: wmr(:)
539  integer(kind=8), intent(out) :: wrepl
540  real(kind=kreal) :: w1(1)
541  integer(kind=kint), allocatable :: rcs(:), disp(:)
542  integer(kind=kint) :: comm, np, r
543  integer(kind=8) :: wpart
544 
545  comm = hecmw_comm_get_comm()
546  np = hecmw_comm_get_size()
547  call hecmw_mf_dist_gmat_words(gmat, wpart, wrepl)
548  allocate(rcs(np), disp(np))
549  do r = 1, np
550  rcs(r) = 1
551  disp(r) = r - 1
552  enddo
553  w1(1) = real(wpart, kind=kreal)
554  call hecmw_allgatherv_real(w1, 1, wmr, rcs, disp, comm)
555  deallocate(rcs, disp)
556  end subroutine mf_gather_matwords
557 
562  subroutine mf_reduce_stats(fct, wpr)
563  implicit none
564  type(hecmwst_mf_factor), intent(inout) :: fct
565  real(kind=kreal), intent(out) :: wpr(:)
566  real(kind=kreal) :: rs(13), rm(3), w1(1)
567  integer(kind=kint), allocatable :: rcs(:), disp(:)
568  integer(kind=kint) :: comm, np, r
569 
570  comm = hecmw_comm_get_comm()
571  np = hecmw_comm_get_size()
572  allocate(rcs(np), disp(np))
573  do r = 1, np
574  rcs(r) = 1
575  disp(r) = r - 1
576  enddo
577  w1(1) = real(fct%factor_words_act, kind=kreal)
578  call hecmw_allgatherv_real(w1, 1, wpr, rcs, disp, comm)
579  deallocate(rcs, disp)
580  rs(1) = real(fct%n_pos, kind=kreal)
581  rs(2) = real(fct%n_neg, kind=kreal)
582  rs(3) = real(fct%n_2x2, kind=kreal)
583  rs(4) = real(fct%n_swap, kind=kreal)
584  rs(5) = real(fct%n_delay, kind=kreal)
585  rs(6) = real(fct%factor_words_act, kind=kreal)
586  rs(7) = real(fct%stack_peak_act, kind=kreal)
587  rs(8) = real(fct%front_peak, kind=kreal)
588  rs(9) = real(fct%blr_words_fr, kind=kreal)
589  rs(10) = real(fct%blr_tiles, kind=kreal)
590  rs(11) = real(fct%blr_tiles_lr, kind=kreal)
591  rs(12) = real(fct%blr_rank_sum, kind=kreal)
592  rs(13) = real(fct%blr_tiles_skip, kind=kreal)
593  call hecmw_allreduce_r_comm(rs, 13, hecmw_sum, comm)
594  rm(1) = real(fct%max_growth, kind=kreal)
595  rm(2) = real(fct%front_words_act, kind=kreal)
596  rm(3) = real(fct%blr_rank_max, kind=kreal)
597  call hecmw_allreduce_r_comm(rm, 3, hecmw_max, comm)
598  fct%n_pos = nint(rs(1), kind=kint)
599  fct%n_neg = nint(rs(2), kind=kint)
600  fct%n_2x2 = nint(rs(3), kind=kint)
601  fct%n_swap = nint(rs(4), kind=kint)
602  fct%n_delay = nint(rs(5), kind=kint)
603  fct%factor_words_act = nint(rs(6), kind=8)
604  fct%stack_peak_act = nint(rs(7), kind=8)
605  fct%front_peak = nint(rs(8), kind=8)
606  fct%blr_words_fr = nint(rs(9), kind=8)
607  fct%blr_tiles = nint(rs(10), kind=8)
608  fct%blr_tiles_lr = nint(rs(11), kind=8)
609  fct%blr_rank_sum = nint(rs(12), kind=8)
610  fct%blr_tiles_skip = nint(rs(13), kind=8)
611  fct%max_growth = nint(rm(1), kind=kint)
612  fct%front_words_act = nint(rm(2), kind=8)
613  fct%blr_rank_max = nint(rm(3), kind=kint)
614  end subroutine mf_reduce_stats
615 
619  subroutine hecmw_mf_compare_builtin(hecMESH, hecMAT, graph, ordering, nerr)
620  implicit none
621  type(hecmwst_local_mesh), intent(in) :: hecmesh
622  type(hecmwst_matrix), intent(in) :: hecmat
623  type(hecmwst_mf_graph), intent(in) :: graph
624  integer(kind=kint), intent(in) :: ordering
625  integer(kind=kint), intent(out) :: nerr
626  type(cholesky_factor) :: fct
627  type(hecmwst_mf_symbolic) :: ref
628  integer(kind=kint), allocatable :: cnt(:)
629  integer(kind=kint) :: n, k, l, ir, pb, myk, mp, nbad_tree, nbad_cnt
630 
631  nerr = 0
632  call setij(hecmesh, hecmat, fct)
633  call matini(fct, ordering, 0, ir)
634  if (ir /= 0) then
635  write(*,'(a,i0)') '[DIRECTmf] compare: built-in MATINI failed, ir = ', ir
636  nerr = 1
637  return
638  endif
639  n = fct%NEQns
640  call hecmw_mf_symbolic_build(graph, fct%IPErm(1:n), 0, ref)
641 
642  nbad_tree = 0
643  do k = 1, n
644  pb = fct%PARent(k)
645  myk = ref%invp(fct%IPErm(k))
646  mp = ref%parent(myk)
647  if (pb == 0 .or. pb == n + 1) then
648  if (mp /= 0) nbad_tree = nbad_tree + 1
649  else
650  if (mp == 0) then
651  nbad_tree = nbad_tree + 1
652  else if (ref%perm(mp) /= fct%IPErm(pb)) then
653  nbad_tree = nbad_tree + 1
654  endif
655  endif
656  enddo
657 
658  allocate(cnt(n))
659  cnt(1:n) = 1
660  do k = 1, n
661  do l = fct%XLNzr(k), fct%XLNzr(k+1) - 1
662  cnt(fct%COLno(l)) = cnt(fct%COLno(l)) + 1
663  enddo
664  enddo
665  nbad_cnt = 0
666  do k = 1, n
667  if (cnt(k) /= ref%colcnt(ref%invp(fct%IPErm(k)))) nbad_cnt = nbad_cnt + 1
668  enddo
669  if (nbad_tree > 0) write(*,'(a,i0)') '[DIRECTmf] compare: elimination tree mismatches = ', nbad_tree
670  if (nbad_cnt > 0) write(*,'(a,i0)') '[DIRECTmf] compare: column count mismatches = ', nbad_cnt
671  nerr = nbad_tree + nbad_cnt
672 
673  deallocate(cnt)
675  deallocate(fct%IROw, fct%JCOl, fct%IPErm, fct%INVp, fct%PARent, fct%NCH, fct%XLNzr, fct%COLno)
676  end subroutine hecmw_mf_compare_builtin
677 
678 end module hecmw_solver_direct_mf
integer(kind=kint) function, public hecmw_mat_get_iterlog(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_timelog(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_loglevel(hecMAT)
MPI distribution layer of the multifrontal solver: the supernode-to-rank mapping and the broadcast of...
subroutine, public hecmw_mf_dist_gather_vec(gmat, v, gv)
Gather the internal parts of a distributed nodal vector into the replicated global vector,...
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,...
Compressed (node level) graph of a block sparse matrix for the multifrontal solver.
subroutine, public hecmw_mf_graph_from_hecmat(hecMAT, graph)
Build the node graph from the nonzero pattern of hecMAT (values are not referenced)....
subroutine, public hecmw_mf_graph_finalize(graph)
Dense kernels of the multifrontal solver, symmetric (LDLt) and unsymmetric (LU) mode.
logical function, public hecmw_mf_kernel_blr_available()
Whether the BLR compression is available (LAPACK build).
Numeric factorization (tiled multifrontal LDLt with threshold pivoting and delayed pivots) and the tr...
subroutine, public hecmw_mf_numeric_solve_mpi(sym, map, fct, b, x)
x = A^-1 b on the supernodes distributed by map; b and x are the replicated global vectors in the ori...
subroutine, public hecmw_mf_numeric_finalize(fct)
subroutine, public hecmw_mf_numeric_print(fct)
integer(kind=kint), parameter, public mf_blr_eta
BLR admissibility: default cluster distance threshold, a contribution tile within it of the pivot clu...
subroutine, public hecmw_mf_numeric_factor(hecMAT, sym, fct, ierr)
Factor the matrix of hecMAT in the order of sym, in LDLt mode (lower part referenced) or in LU mode w...
subroutine, public hecmw_mf_numeric_admis_bcast(fct, root)
Broadcast the admissibility cache from the rank that built it (the distributed driver builds the grap...
subroutine, public hecmw_mf_numeric_solve(sym, fct, b, x)
x = A^-1 b with the factor; b and x are in the original DOF numbering. The forward solve works on the...
subroutine, public hecmw_mf_numeric_init(graph, sym, tile, blr, eta, fct)
Estimates of the factor and stack sizes from the symbolic structure and the work space; tile is the t...
subroutine, public hecmw_mf_numeric_factor_mpi(hecMAT, sym, map, fct, ierr)
Factor the matrix with the supernodes distributed by map: every rank first factors its subtrees with ...
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 ...
HECMW_ORDERING is a program for fill-reducing ordering.
subroutine, public hecmw_ordering_gen(Neqns, Nttbr, Xadj, Adj0, Perm, Invp, opt, loglevel)
hecmw_ordering_gen
Multifrontal direct solver (METHOD=DIRECTmf): LDLt with threshold pivoting for symmetric (possibly in...
subroutine, public hecmw_solve_direct_mf(hecMESH, hecMAT, imsg)
subroutine, public hecmw_mf_compare_builtin(hecMESH, hecMAT, graph, ordering, nerr)
Compare the elimination tree and the column counts with the symbolic stage of the built-in direct sol...
HECMW_SOLVE_DIRECT is a program for the matrix direct solver.
subroutine, public matini(FCT, ordering, loglevel, Ir)
MATINI initializes storage for sparse matrix solver.
subroutine, public setij(hecMESH, hecMAT, FCT)
SETIJ.
subroutine, public hecmw_matresid(hecMESH, hecMAT, X, B, R, COMMtime)
subroutine hecmw_innerproduct_r(hecMESH, ndof, X, Y, sum, COMMtime)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=kint), parameter hecmw_sum
subroutine hecmw_abort(comm, code)
integer(kind=kint) function hecmw_comm_get_size()
integer(kind=4), parameter kint
integer(kind=kint) function hecmw_comm_get_comm()
integer(kind=kint), parameter hecmw_max
integer(kind=4), parameter kreal
integer(kind=kint) function hecmw_comm_get_rank()
real(kind=kreal) function hecmw_wtime()
subroutine hecmw_update_r(hecMESH, val, n, m)
subroutine hecmw_allgatherv_real(sbuf, sc, rbuf, rcs, disp, comm)
subroutine hecmw_allreduce_r_comm(val, n, ntag, comm)