FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
hecmw_solver_CG.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***
8 !C*** module hecmw_solver_CG
9 !C***
10 !C
12 
13  public :: hecmw_solve_cg
14 
15 contains
16  !C
17  !C*** CG_nn
18  !C
19  subroutine hecmw_solve_cg( hecMESH, hecMAT, ITER, RESID, error, &
20  & Tset, Tsol, Tcomm )
21 
22  use hecmw_util
24  use m_hecmw_comm_f
29  use hecmw_precond
30  use hecmw_jad_type
32 
33  implicit none
34 
35  type(hecmwst_local_mesh) :: hecmesh
36  type(hecmwst_matrix) :: hecmat
37  integer(kind=kint ), intent(inout):: iter, error
38  real (kind=kreal), intent(inout):: resid, tset, tsol, tcomm
39 
40  integer(kind=kint ) :: n, np, ndof, nndof
41  integer(kind=kint ) :: my_rank
42  integer(kind=kint ) :: iterlog, timelog
43  real(kind=kreal), pointer :: b(:), x(:)
44 
45  real(kind=kreal), dimension(:,:), allocatable :: ww
46 
47  integer(kind=kint), parameter :: r= 1
48  integer(kind=kint), parameter :: z= 2
49  integer(kind=kint), parameter :: q= 2
50  integer(kind=kint), parameter :: p= 3
51  integer(kind=kint), parameter :: wk= 4
52 
53  integer(kind=kint ) :: maxit
54 
55  ! local variables
56  real (kind=kreal) :: tol
57  real (kind=kreal)::s_time,s1_time,e_time,e1_time, start_time, end_time
58  real (kind=kreal)::bnrm2
59  real (kind=kreal)::rho,rho1,beta,c1,alpha,dnrm2
60  real (kind=kreal)::t_max,t_min,t_avg,t_sd
61  integer(kind=kint) ::estcond
62  real (kind=kreal), allocatable::d(:),e(:)
63  real (kind=kreal)::alpha1
64  integer(kind=kint) :: n_indef_precond
65 
66  integer(kind=kint) :: n_iter_recompute_r
67  integer(kind=kint), parameter :: n_iter_recompute_r_default= 50
68 
69  call hecmw_barrier(hecmesh)
70  s_time= hecmw_wtime()
71 
72  !C===
73  !C +-------+
74  !C | INIT. |
75  !C +-------+
76  !C===
77  n = hecmat%N
78  np = hecmat%NP
79  ndof = hecmat%NDOF
80  nndof = n * ndof
81  my_rank = hecmesh%my_rank
82  x => hecmat%X
83  b => hecmat%B
84 
85  iterlog = hecmw_mat_get_iterlog( hecmat )
86  timelog = hecmw_mat_get_timelog( hecmat )
87  maxit = hecmw_mat_get_iter( hecmat )
88  tol = hecmw_mat_get_resid( hecmat )
89  estcond = hecmw_mat_get_estcond( hecmat )
90 
91  n_iter_recompute_r = hecmw_mat_get_recompute_residual( hecmat )
92  if (n_iter_recompute_r == 0) n_iter_recompute_r = n_iter_recompute_r_default
93  !C----- negative: never recompute periodically. ITER stops at MAXIT, so mod() below is never 0
94  if (n_iter_recompute_r < 0) n_iter_recompute_r = maxit + 1
95 
96  error = 0
97  n_indef_precond = 0
98  rho1 = 0.0d0
99  alpha1 = 0.0d0
100  beta = 0.0d0
101 
102  allocate (ww(ndof*np, 4))
103  ww = 0.d0
104 
105  !C
106  !C-- SCALING
107  call hecmw_solver_scaling_fw(hecmesh, hecmat, tcomm)
108 
109  !C
110  !C-- matrix integration for OpenACC
111  !C
112  !C @note:
113  !C Combine hecMAT%AL, D, and AU into a single matrix for GPU execution.
114  !C This is a no-op for CPU builds.
115  call hecmw_mat_integrate(hecmat)
116 
117  if (hecmw_mat_get_usejad(hecmat).ne.0) then
118  call hecmw_jad_init(hecmat)
119  endif
120  call hecmw_matvec_setup(hecmesh, hecmat)
121 
122  if (estcond /= 0 .and. hecmesh%my_rank == 0) then
123  allocate(d(maxit),e(maxit-1))
124  endif
125  !C===
126  !C +----------------------+
127  !C | SETUP PRECONDITIONER |
128  !C +----------------------+
129  !C===
130  call hecmw_precond_setup(hecmat, hecmesh, 1)
131 
132  !C===
133  !C +---------------------+
134  !C | {r0}= {b} - [A]{x0} |
135  !C +---------------------+
136  !C===
137  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,r), tcomm)
138 
139  !C-- compute ||{b}||
140  call hecmw_innerproduct_r(hecmesh, ndof, b, b, bnrm2, tcomm)
141  if (bnrm2.eq.0.d0) then
142  iter = 0
143  maxit = 0
144  resid = 0.d0
145  x = 0.d0
146  endif
147 
148  e_time = hecmw_wtime()
149  if (timelog.eq.2) then
150  call hecmw_time_statistics(hecmesh, e_time - s_time, &
151  t_max, t_min, t_avg, t_sd)
152  if (hecmesh%my_rank.eq.0) then
153  write(*,*) 'Time solver setup'
154  write(*,*) ' Max :',t_max
155  write(*,*) ' Min :',t_min
156  write(*,*) ' Avg :',t_avg
157  write(*,*) ' Std Dev :',t_sd
158  endif
159  tset = t_max
160  else
161  tset = e_time - s_time
162  endif
163 
164  tcomm = 0.d0
165  call hecmw_barrier(hecmesh)
166  s1_time = hecmw_wtime()
167  !C
168  !C************************************************* Conjugate Gradient Iteration start
169  !C
170  do iter = 1, maxit
171 
172  !C===
173  !C +----------------+
174  !C | {z}= [Minv]{r} |
175  !C +----------------+
176  !C===
177  call hecmw_precond_apply(hecmesh, hecmat, ww(:,r), ww(:,z), ww(:,wk), tcomm)
178 
179 
180  !C===
181  !C +---------------+
182  !C | {RHO}= {r}{z} |
183  !C +---------------+
184  !C===
185  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,z), rho, tcomm)
186  ! if RHO is NaN or Inf then no converge
187  if (rho == 0.d0) then
188  ! converged due to RHO==0
189  exit
190  elseif (iter > 1 .and. rho*rho1 <= 0) then
191  n_indef_precond = n_indef_precond + 1
192  if (n_indef_precond >= 10) then
193  ! diverged due to indefinite preconditioner
195  exit
196  endif
197  elseif (rho /= rho) then ! RHO is NaN
199  exit
200  else
201  n_indef_precond = 0
202  endif
203 
204  !C===
205  !C +-----------------------------+
206  !C | {p} = {z} if ITER=1 |
207  !C | BETA= RHO / RHO1 otherwise |
208  !C +-----------------------------+
209  !C===
210  if ( iter.eq.1 ) then
211  call hecmw_copy_r(nndof, ww(:,z), ww(:,p))
212  else
213  beta = rho / rho1
214  call hecmw_xpay_r(nndof, beta, ww(:,z), ww(:,p))
215  endif
216 
217  !C===
218  !C +--------------+
219  !C | {q}= [A] {p} |
220  !C +--------------+
221  !C===
222  call hecmw_matvec(hecmesh, hecmat, ww(:,p), ww(:,q), tcomm)
223 
224  !C===
225  !C +---------------------+
226  !C | ALPHA= RHO / {p}{q} |
227  !C +---------------------+
228  !C===
229  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,p), ww(:,q), c1, tcomm)
230  ! if C1 is NaN or Inf, no converge
231  if (c1 <= 0) then
232  ! diverged due to indefinite or negative definite matrix
234  exit
235  elseif (c1 /= c1) then ! C1 is NaN
237  exit
238  endif
239 
240  alpha= rho / c1
241 
242  !C===
243  !C +----------------------+
244  !C | {x}= {x} + ALPHA*{p} |
245  !C | {r}= {r} - ALPHA*{q} |
246  !C +----------------------+
247  !C===
248  call hecmw_axpy_r(nndof, alpha, ww(:,p), x)
249 
250  if ( mod(iter,n_iter_recompute_r)==0 ) then
251  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,r), tcomm)
252  else
253  call hecmw_axpy_r(nndof, -alpha, ww(:,q), ww(:,r))
254  endif
255 
256  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,r), dnrm2, tcomm)
257 
258  resid= dsqrt(dnrm2/bnrm2)
259 
260  !C##### ITERATION HISTORY
261  if (my_rank.eq.0.and.iterlog.eq.1) write (*,'(i7, 1pe16.6)') iter, resid
262  !C#####
263 
264  if (estcond /= 0 .and. hecmesh%my_rank == 0) then
265  if (iter == 1) then
266  d(1) = 1.d0 / alpha
267  else
268  d(iter) = 1.d0 / alpha + beta / alpha1
269  e(iter-1) = sqrt(beta) / alpha1
270  endif
271  alpha1 = alpha
272  if (mod(iter,estcond) == 0) call hecmw_estimate_condition_cg(iter, d, e)
273  endif
274 
275  if ( resid.le.tol ) then
276  if ( mod(iter,n_iter_recompute_r)==0 ) exit
277  !C----- recompute R to make sure it is really converged
278  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,r), tcomm)
279  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,r), dnrm2, tcomm)
280  resid= dsqrt(dnrm2/bnrm2)
281  if ( resid.le.tol ) exit
282  endif
283  if ( iter .eq.maxit ) error = hecmw_solver_error_noconv_maxit
284 
285  rho1 = rho
286 
287  enddo
288  !C
289  !C************************************************* Conjugate Gradient Iteration end
290  !C
291  call hecmw_solver_scaling_bk(hecmat)
292  !C
293  !C-- INTERFACE data EXCHANGE
294  !C
295  start_time= hecmw_wtime()
296  call hecmw_update_r (hecmesh, x, hecmat%NP, hecmat%NDOF)
297  end_time = hecmw_wtime()
298  tcomm = tcomm + end_time - start_time
299 
300  deallocate (ww)
301  !call hecmw_precond_clear(hecMAT)
302 
303  call hecmw_matvec_teardown(hecmat)
304  if (hecmw_mat_get_usejad(hecmat).ne.0) then
305  call hecmw_jad_finalize(hecmat)
306  endif
307 
308  if (estcond /= 0 .and. error == 0 .and. hecmesh%my_rank == 0) then
309  call hecmw_estimate_condition_cg(iter, d, e)
310  deallocate(d, e)
311  endif
312 
313  e1_time = hecmw_wtime()
314  if (timelog.eq.2) then
315  call hecmw_time_statistics(hecmesh, e1_time - s1_time, &
316  t_max, t_min, t_avg, t_sd)
317  if (hecmesh%my_rank.eq.0) then
318  write(*,*) 'Time solver iterations'
319  write(*,*) ' Max :',t_max
320  write(*,*) ' Min :',t_min
321  write(*,*) ' Avg :',t_avg
322  write(*,*) ' Std Dev :',t_sd
323  endif
324  tsol = t_max
325  else
326  tsol = e1_time - s1_time
327  endif
328 
329  end subroutine hecmw_solve_cg
330 
331 end module hecmw_solver_cg
subroutine, public hecmw_estimate_condition_cg(ITER, D, E)
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.
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_recompute_residual(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_cg(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_xpay_r(n, alpha, X, Y)
subroutine hecmw_innerproduct_r(hecMESH, ndof, X, Y, sum, COMMtime)
subroutine hecmw_axpy_r(n, alpha, X, Y)
subroutine hecmw_copy_r(n, 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_diverge_pc
integer(kind=kint), parameter hecmw_solver_error_diverge_nan
integer(kind=kint), parameter hecmw_solver_error_noconv_maxit
integer(kind=kint), parameter hecmw_solver_error_diverge_mat