FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
hecmw_solver_GMRES.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2019 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
5 
6 !C***
7 !C*** module hecmw_solver_GMRES
8 !C***
9 !
11 
12  public :: hecmw_solve_gmres
13 
14 contains
15  !C
16  !C*** hecmw_solve_GMRES
17  !C
18  subroutine hecmw_solve_gmres( hecMESH, hecMAT, ITER, RESID, error, &
19  & Tset, Tsol, Tcomm )
20  use hecmw_util
22  use m_hecmw_comm_f
27  use hecmw_precond
28  use hecmw_jad_type
30 
31  implicit none
32 
33  type(hecmwst_local_mesh) :: hecmesh
34  type(hecmwst_matrix) :: hecmat
35  integer(kind=kint ), intent(inout):: iter, error
36  real (kind=kreal), intent(inout):: resid, tset, tsol, tcomm
37 
38  integer(kind=kint ) :: n, np, ndof, nndof
39  integer(kind=kint ) :: my_rank
40  integer(kind=kint ) :: iterlog, timelog
41  real(kind=kreal), pointer :: b(:), x(:)
42 
43  real(kind=kreal), dimension(:,:), allocatable :: ww
44 
45  integer(kind=kint ) :: maxit, nrest
46 
47  real (kind=kreal) :: tol
48 
49  real (kind=kreal), dimension(:), allocatable :: ss
50  real (kind=kreal), dimension(:,:), allocatable :: h
51 
52  integer(kind=kint ) :: cs, sn
53 
54  real (kind=kreal) zero, one
55  parameter( zero = 0.0d+0, one = 1.0d+0 )
56 
57  integer(kind=kint ) :: nrk,i,k,kk,jj,info,ik
58  integer(kind=kint ) :: irow
59  real (kind=kreal) :: s_time,e_time,s1_time,e1_time
60  real (kind=kreal) :: ldh,ldw,bnrm2,dnrm2,rnorm
61  real (kind=kreal) :: commtime,comptime, coef,val,vcs,vsn,dtemp,aa,bb,r0,scale,rr
62  integer(kind=kint ) :: estcond
63  real (kind=kreal) :: t_max,t_min,t_avg,t_sd
64 
65  integer(kind=kint), parameter :: r = 1
66  integer(kind=kint), parameter :: zp = r + 1
67  integer(kind=kint), parameter :: zq = r + 2
68  integer(kind=kint), parameter :: s = r + 3
69  integer(kind=kint), parameter :: w = s + 1
70  integer(kind=kint), parameter :: y = w
71  integer(kind=kint), parameter :: av = y + 1
72  integer(kind=kint), parameter :: v = av + 1
73 
74  call hecmw_barrier(hecmesh)
75  s_time= hecmw_wtime()
76  !C
77  !C-- INIT.
78  n = hecmat%N
79  np = hecmat%NP
80  ndof = hecmat%NDOF
81  nndof = n * ndof
82  my_rank = hecmesh%my_rank
83  x => hecmat%X
84  b => hecmat%B
85 
86  iterlog = hecmw_mat_get_iterlog( hecmat )
87  timelog = hecmw_mat_get_timelog( hecmat )
88  maxit = hecmw_mat_get_iter( hecmat )
89  tol = hecmw_mat_get_resid( hecmat )
90  nrest = hecmw_mat_get_nrest( hecmat )
91  estcond = hecmw_mat_get_estcond( hecmat )
92 
93  if (nrest >= ndof*np-1) nrest = ndof*np-2
94 
95  error= 0
96  nrk= nrest + 7
97 
98  allocate (h(nrk,nrk))
99  allocate (ww(ndof*np,nrk))
100  allocate (ss(nrk))
101 
102  commtime= 0.d0
103  comptime= 0.d0
104 
105  ldh= nrest + 2
106  ldw= n
107 
108  !C
109  !C-- Store the Givens parameters in matrix H.
110  cs= nrest + 1
111  sn= cs + 1
112 
113  !C
114  !C-- SCALING
115  call hecmw_solver_scaling_fw(hecmesh, hecmat, tcomm)
116 
117  !C
118  !C-- matrix integration for OpenACC
119  !C
120  !C @note:
121  !C Combine hecMAT%AL, D, and AU into a single matrix for GPU execution.
122  !C This is a no-op for CPU builds.
123  call hecmw_mat_integrate(hecmat)
124 
125  if (hecmw_mat_get_usejad(hecmat).ne.0) then
126  call hecmw_jad_init(hecmat)
127  endif
128  call hecmw_matvec_setup(hecmesh, hecmat)
129 
130  !C===
131  !C +----------------------+
132  !C | SETUP PRECONDITIONER |
133  !C +----------------------+
134  !C===
135  call hecmw_precond_setup(hecmat, hecmesh, 0)
136 
137  !C
138  !C
139  !C +--------------------+
140  !C | {r}= {b} - [A]{x0} |
141  !C +--------------------+
142  !C===
143  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,r), tcomm)
144  !C===
145 
146  call hecmw_innerproduct_r(hecmesh, ndof, b, b, bnrm2, tcomm)
147  if (bnrm2.eq.0.d0) then
148  iter = 0
149  maxit = 0
150  resid = 0.d0
151  x = 0.d0
152  endif
153 
154  e_time= hecmw_wtime()
155  if (timelog.eq.2) then
156  call hecmw_time_statistics(hecmesh, e_time - s_time, &
157  t_max, t_min, t_avg, t_sd)
158  if (hecmesh%my_rank.eq.0) then
159  write(*,*) 'Time solver setup'
160  write(*,*) ' Max :',t_max
161  write(*,*) ' Min :',t_min
162  write(*,*) ' Avg :',t_avg
163  write(*,*) ' Std Dev :',t_sd
164  endif
165  tset = t_max
166  else
167  tset = e_time - s_time
168  endif
169  !C===
170 
171  call hecmw_barrier(hecmesh)
172  s1_time= hecmw_wtime()
173  iter= 0
174 
175  outer: do
176 
177  !C
178  !C************************************************ GMRES Iteration
179  !C
180  i= 0
181  !C
182  !C +---------------+
183  !C | {v1}= {r}/|r| |
184  !C +---------------+
185  !C===
186  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,r), dnrm2, tcomm)
187  if (dnrm2 == 0.d0) exit ! converged
188 
189  rnorm= dsqrt(dnrm2)
190  coef= one/rnorm
191  call hecmw_axpby_r(nndof, coef, 0.d0, ww(:,r), ww(:,v))
192  !C===
193 
194  !C
195  !C +--------------+
196  !C | {s}= |r|{e1} |
197  !C +--------------+
198  !C===
199  call hecmw_scale_r(nndof, zero, ww(:,s))
200  ww(1 ,s) = rnorm
201  !C===
202 
203  !C************************************************ GMRES(m) restart
204  do i = 1, nrest
205  iter= iter + 1
206 
207  !C
208  !C +-------------------+
209  !C | {w}= [A][Minv]{v} |
210  !C +-------------------+
211  !C===
212  call hecmw_precond_apply(hecmesh, hecmat, ww(:,v+i-1), ww(:,zq), ww(:,zp), tcomm)
213 
214  call hecmw_matvec(hecmesh, hecmat, ww(:,zq), ww(:,w), tcomm)
215  !C===
216 
217  !C
218  !C +------------------------------+
219  !C | ORTH. BASIS by GRAMM-SCHMIDT |
220  !C +------------------------------+
221  !C Construct the I-th column of the upper Hessenberg matrix H
222  !C using the Gram-Schmidt process on V and W.
223  !C===
224  do k= 1, i
225  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,w), ww(:,v+k-1), val, tcomm)
226 
227  call hecmw_axpy_r(nndof, -val, ww(:,v+k-1), ww(:,w))
228  h(k,i)= val
229  enddo
230 
231  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,w), ww(:,w), val, tcomm)
232  if (val == 0.d0) exit ! converged
233 
234  h(i+1,i)= dsqrt(val)
235  coef= one / h(i+1,i)
236  call hecmw_axpby_r(nndof, coef, 0.d0, ww(:,w), ww(:,v+i+1-1))
237  !C===
238 
239  !C
240  !C +-----------------+
241  !C | GIVENS ROTARION |
242  !C +-----------------+
243  !C===
244 
245  !C
246  !C-- Plane Rotation
247  do k = 1, i-1
248  vcs= h(k,cs)
249  vsn= h(k,sn)
250  dtemp = vcs*h(k ,i) + vsn*h(k+1,i)
251  h(k+1,i)= vcs*h(k+1,i) - vsn*h(k ,i)
252  h(k ,i)= dtemp
253  enddo
254 
255  !C
256  !C-- Construct Givens Plane Rotation
257  aa = h(i ,i)
258  bb = h(i+1,i)
259  r0= bb
260  if (dabs(aa).gt.dabs(bb)) r0= aa
261  scale= dabs(aa) + dabs(bb)
262 
263  if (scale.ne.0.d0) then
264  rr= scale * dsqrt((aa/scale)**2+(bb/scale)**2)
265  rr= dsign(1.d0,r0)*rr
266  h(i,cs)= aa/rr
267  h(i,sn)= bb/rr
268  else
269  h(i,cs)= 1.d0
270  h(i,sn)= 0.d0
271  rr = 0.d0
272  endif
273 
274  !C
275  !C-- Plane Rotation
276  vcs= h(i,cs)
277  vsn= h(i,sn)
278  dtemp = vcs*h(i ,i) + vsn*h(i+1,i)
279  h(i+1,i)= vcs*h(i+1,i) - vsn*h(i ,i)
280  h(i ,i)= dtemp
281 
282  dtemp = vcs*ww(i ,s) + vsn*ww(i+1,s)
283  ww(i+1,s)= vcs*ww(i+1,s) - vsn*ww(i ,s)
284  ww(i ,s)= dtemp
285 
286  resid = dabs( ww(i+1,s))/dsqrt(bnrm2)
287 
288  if (my_rank.eq.0 .and. iterlog.eq.1) &
289  & write (*, '(2i8, 1pe16.6)') iter,i+1, resid
290 
291  if (estcond /= 0 .and. hecmesh%my_rank == 0) then
292  if (mod(iter,estcond) == 0) call hecmw_estimate_condition_gmres(i, h)
293  endif
294 
295  if ( resid.le.tol ) then
296  !C-- [H]{y}= {s_tld}
297  do ik= 1, i
298  ss(ik)= ww(ik,s)
299  enddo
300  irow= i
301  ww(irow,y)= ss(irow) / h(irow,irow)
302 
303  do kk= irow-1, 1, -1
304  do jj= irow, kk+1, -1
305  ss(kk)= ss(kk) - h(kk,jj)*ww(jj,y)
306  enddo
307  ww(kk,y)= ss(kk) / h(kk,kk)
308  enddo
309 
310  !C-- {x}= {x} + {y}{V}
311  call hecmw_scale_r(nndof, 0.d0, ww(:,av))
312 
313  jj= irow
314  do jj= 1, irow
315  call hecmw_axpy_r(nndof, ww(jj,y), ww(:,v+jj-1), ww(:,av))
316  enddo
317 
318  call hecmw_precond_apply(hecmesh, hecmat, ww(:,av), ww(:,zq), ww(:,zp), tcomm)
319 
320  call hecmw_axpy_r(nndof, 1.d0, ww(:,zq), x)
321 
322  exit outer
323  endif
324 
325  if ( iter.gt.maxit ) then
327  exit outer
328  end if
329  end do
330  !C===
331 
332  !C
333  !C +------------------+
334  !C | CURRENT SOLUTION |
335  !C +------------------+
336  !C===
337 
338  !C-- [H]{y}= {s_tld}
339  do ik= 1, nrest
340  ss(ik)= ww(ik,s)
341  enddo
342  irow= nrest
343  ww(irow,y)= ss(irow) / h(irow,irow)
344 
345  do kk= irow-1, 1, -1
346  do jj= irow, kk+1, -1
347  ss(kk)= ss(kk) - h(kk,jj)*ww(jj,y)
348  enddo
349  ww(kk,y)= ss(kk) / h(kk,kk)
350  enddo
351 
352  !C-- {x}= {x} + {y}{V}
353  call hecmw_scale_r(nndof, 0.d0, ww(:,av))
354 
355  jj= irow
356  do jj= 1, irow
357  call hecmw_axpy_r(nndof, ww(jj,y), ww(:,v+jj-1), ww(:,av))
358  enddo
359 
360  call hecmw_precond_apply(hecmesh, hecmat, ww(:,av), ww(:,zq), ww(:,zp), tcomm)
361 
362  call hecmw_axpy_r(nndof, 1.d0, ww(:,zq), x)
363 
364  !C
365  !C-- Compute residual vector R, find norm, then check for tolerance.
366  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,r), tcomm)
367 
368  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,r), dnrm2, tcomm)
369 
370  ww(i+1,s)= dsqrt(dnrm2/bnrm2)
371  resid = ww( i+1,s )
372 
373  if ( resid.le.tol ) exit outer
374  if ( iter .gt.maxit ) then
376  exit outer
377  end if
378  !C
379  !C-- RESTART
380  end do outer
381 
382  !C
383  !C-- iteration FAILED
384 
385  if (error == hecmw_solver_error_noconv_maxit) then
386  info = iter
387 
388  !C-- [H]{y}= {s_tld}
389  do ik= 1, i
390  ss(ik)= ww(ik,s)
391  enddo
392  irow= i
393  ww(irow,y)= ss(irow) / h(irow,irow)
394 
395  do kk= irow-1, 1, -1
396  do jj= irow, kk+1, -1
397  ss(kk)= ss(kk) - h(kk,jj)*ww(jj,y)
398  enddo
399  ww(kk,y)= ss(kk) / h(kk,kk)
400  enddo
401 
402  !C-- {x}= {x} + {y}{V}
403  call hecmw_scale_r(nndof, 0.d0, ww(:,av))
404 
405  jj= irow
406  do jj= 1, irow
407  call hecmw_axpy_r(nndof, ww(jj,y), ww(:,v+jj-1), ww(:,av))
408  enddo
409 
410  call hecmw_precond_apply(hecmesh, hecmat, ww(:,av), ww(:,zq), ww(:,zp), tcomm)
411 
412  call hecmw_axpy_r(nndof, 1.d0, ww(:,zq), x)
413  end if
414 
415  call hecmw_solver_scaling_bk(hecmat)
416 
417  if (estcond /= 0 .and. hecmesh%my_rank == 0) then
419  endif
420  !C
421  !C-- INTERFACE data EXCHANGE
422  s_time = hecmw_wtime()
423  call hecmw_update_r (hecmesh, x, hecmat%NP, hecmat%NDOF)
424  e_time = hecmw_wtime()
425  tcomm = tcomm + e_time - s_time
426 
427  deallocate (h, ww, ss)
428  !call hecmw_precond_clear(hecMAT)
429 
430  call hecmw_matvec_teardown(hecmat)
431  if (hecmw_mat_get_usejad(hecmat).ne.0) then
432  call hecmw_jad_finalize(hecmat)
433  endif
434 
435  e1_time= hecmw_wtime()
436  if (timelog.eq.2) then
437  call hecmw_time_statistics(hecmesh, e1_time - s1_time, &
438  t_max, t_min, t_avg, t_sd)
439  if (hecmesh%my_rank.eq.0) then
440  write(*,*) 'Time solver iterations'
441  write(*,*) ' Max :',t_max
442  write(*,*) ' Min :',t_min
443  write(*,*) ' Avg :',t_avg
444  write(*,*) ' Std Dev :',t_sd
445  endif
446  tsol = t_max
447  else
448  tsol = e1_time - s1_time
449  endif
450 
451  end subroutine hecmw_solve_gmres
452 
453 end module hecmw_solver_gmres
subroutine, public hecmw_estimate_condition_gmres(I, H)
Jagged Diagonal Matrix storage for vector processors. Original code was provided by JAMSTEC.
Definition: hecmw_jadm.f90:8
subroutine, public hecmw_jad_init(hecMAT)
Definition: hecmw_jadm.f90:29
subroutine, public hecmw_jad_finalize(hecMAT)
Definition: hecmw_jadm.f90:42
subroutine, public hecmw_mat_integrate(hecMAT)
Integrate matrix components into a single array for efficient access.
integer(kind=kint) function, public hecmw_mat_get_nrest(hecMAT)
real(kind=kreal) function, public hecmw_mat_get_resid(hecMAT)
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_estcond(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_usejad(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_iter(hecMAT)
subroutine, public hecmw_precond_setup(hecMAT, hecMESH, sym)
subroutine, public hecmw_precond_apply(hecMESH, hecMAT, R, Z, ZP, COMMtime)
subroutine, public hecmw_solve_gmres(hecMESH, hecMAT, ITER, RESID, error, Tset, Tsol, Tcomm)
subroutine, public hecmw_matvec_teardown(hecMAT)
subroutine, public hecmw_matvec_setup(hecMESH, hecMAT)
subroutine, public hecmw_matresid(hecMESH, hecMAT, X, B, R, COMMtime)
subroutine, public hecmw_matvec(hecMESH, hecMAT, X, Y, COMMtime)
subroutine hecmw_innerproduct_r(hecMESH, ndof, X, Y, sum, COMMtime)
subroutine hecmw_scale_r(n, alpha, X)
subroutine hecmw_axpby_r(n, alpha, beta, X, Y)
subroutine hecmw_axpy_r(n, alpha, X, Y)
subroutine hecmw_time_statistics(hecMESH, time, t_max, t_min, t_avg, t_sd)
subroutine, public hecmw_solver_scaling_fw(hecMESH, hecMAT, COMMtime)
subroutine, public hecmw_solver_scaling_bk(hecMAT)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=4), parameter kreal
real(kind=kreal) function hecmw_wtime()
subroutine hecmw_update_r(hecMESH, val, n, m)
subroutine hecmw_barrier(hecMESH)
integer(kind=kint), parameter hecmw_solver_error_noconv_maxit