FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
hecmw_solver_CR.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_CR
8 !C***
9 !
11 
12  public :: hecmw_solve_cr
13 
14 contains
15  !C
16  !C*** hecmw_solve_CR
17  !C
18  subroutine hecmw_solve_cr(hecMESH, hecMAT, ITER, RESID, error, Tset, Tsol, Tcomm)
19  use hecmw_util
21  use m_hecmw_comm_f
26  use hecmw_precond
27  use hecmw_jad_type
28 
29  implicit none
30 
31  type(hecmwst_local_mesh) :: hecmesh
32  type(hecmwst_matrix) :: hecmat
33  integer(kind=kint ), intent(inout):: iter, error
34  real (kind=kreal), intent(inout):: resid, tset, tsol, tcomm
35 
36  integer(kind=kint ) :: n, np, ndof, nndof
37  integer(kind=kint ) :: my_rank
38  integer(kind=kint ) :: iterlog, timelog
39  real(kind=kreal), pointer :: b(:), x(:)
40 
41  real(kind=kreal), dimension(:,:), allocatable :: ww
42 
43  integer(kind=kint ) :: maxit
44 
45  ! local variables
46  real (kind=kreal):: tol
47  integer(kind=kint )::i
48  real (kind=kreal)::s_time, s1_time, e_time, e1_time, start_time, end_time
49  real (kind=kreal)::bnrm2, rtar, rtar_old, aptap
50  real (kind=kreal)::alpha, beta, dnrm2, dnrm2_true
51  real (kind=kreal)::resid_rec, resid_true
52  real (kind=kreal)::t_max, t_min, t_avg, t_sd
53  logical :: true_checked
54 
55  ! PCR vector definitions
56  integer(kind=kint), parameter :: r = 1 ! {z} = [Minv]{rt}
57  integer(kind=kint), parameter :: p = 2 ! search direction {p}
58  integer(kind=kint), parameter :: ap = 3 ! [A]{p}
59  integer(kind=kint), parameter :: az = 4 ! [A]{z}
60  integer(kind=kint), parameter :: wk = 4 ! preconditioner / true-residual workspace; shares AZ column (lifetimes disjoint)
61  integer(kind=kint), parameter :: map = 5 ! [Minv][A]{p}
62  integer(kind=kint), parameter :: rt = 6 ! recursive residual {rt} = {b} - [A]{x}
63 
64  integer(kind=kint), parameter :: n_iter_check_true_r = 100
65 
66  call hecmw_barrier(hecmesh)
67  s_time = hecmw_wtime()
68 
69  !C===
70  !C +-------+
71  !C | INIT. |
72  !C +-------+
73  !C===
74  n = hecmat%N
75  np = hecmat%NP
76  ndof = hecmat%NDOF
77  nndof = n * ndof
78  my_rank = hecmesh%my_rank
79  x => hecmat%X
80  b => hecmat%B
81 
82  iterlog = hecmw_mat_get_iterlog( hecmat )
83  timelog = hecmw_mat_get_timelog( hecmat )
84  maxit = hecmw_mat_get_iter( hecmat )
85  tol = hecmw_mat_get_resid( hecmat )
86 
87  error = 0
88  rtar_old = 0.0d0
89 
90  allocate (ww(ndof*np, 6))
91  ww = 0.d0
92 
93  !C
94  !C-- SCALING
95  call hecmw_solver_scaling_fw(hecmesh, hecmat, tcomm)
96 
97  if (hecmw_mat_get_usejad(hecmat).ne.0) then
98  call hecmw_jad_init(hecmat)
99  endif
100  call hecmw_matvec_setup(hecmesh, hecmat)
101 
102  !C===
103  !C +----------------------+
104  !C | SETUP PRECONDITIONER |
105  !C +----------------------+
106  !C===
107  call hecmw_precond_setup(hecmat, hecmesh, 1)
108 
109  !C===
110  !C +-----------------------+
111  !C | {rt}= {b} - [A]{x} |
112  !C +-----------------------+
113  !C===
114  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,rt), tcomm)
115 
116  !C-- compute ||{b}||
117  call hecmw_innerproduct_r(hecmesh, ndof, b, b, bnrm2, tcomm)
118  if (bnrm2.eq.0.d0) then
119  iter = 0
120  maxit = 0
121  resid = 0.d0
122  x = 0.d0
123  else
124  !C-- Check the true initial residual before constructing PCR vectors
125  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,rt), ww(:,rt), dnrm2, tcomm)
126  resid = dsqrt(dnrm2/bnrm2)
127  if (resid.le.tol) then
128  iter = 0
129  maxit = 0
130  else
131  !C-- {z}= [Minv]{rt}
132  call hecmw_precond_apply(hecmesh, hecmat, ww(:,rt), ww(:,r), ww(:,wk), tcomm)
133 
134  !C-- {p}= {z}
135  call hecmw_copy_r(nndof, ww(:,r), ww(:,p))
136 
137  !C-- {az}= [A]{z}, {ap}= {az}
138  call hecmw_matvec(hecmesh, hecmat, ww(:,r), ww(:,az), tcomm)
139  call hecmw_copy_r(nndof, ww(:,az), ww(:,ap))
140 
141  !C-- rTAr_old= {z}^T[A]{z}
142  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,az), rtar_old, tcomm)
143  if (rtar_old /= rtar_old) then
145  iter = 0
146  maxit = 0
147  elseif (rtar_old <= 0.0d0) then
149  iter = 0
150  maxit = 0
151  endif
152  endif
153  endif
154 
155  e_time = hecmw_wtime()
156  if (timelog.eq.2) then
157  call hecmw_time_statistics(hecmesh, e_time - s_time, 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 
170  tcomm = 0.d0
171  call hecmw_barrier(hecmesh)
172  s1_time = hecmw_wtime()
173 
174  !C
175  !C*************************************************************** Iteration begins
176  !C
177  do iter = 1, maxit
178 
179  !C===
180  !C +-------------------------+
181  !C | {map}= [Minv]{ap} |
182  !C +-------------------------+
183  !C===
184  ! AZ and WK share one column because [A]{z} is dead while the preconditioner workspace is needed.
185  call hecmw_precond_apply(hecmesh, hecmat, ww(:,ap), ww(:,map), ww(:,wk), tcomm)
186 
187  !C===
188  !C +--------------------------------+
189  !C | ApTAp= {ap}^T[Minv]{ap} |
190  !C +--------------------------------+
191  !C===
192  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,ap), ww(:,map), aptap, tcomm)
193 
194  if (aptap /= aptap) then
196  exit
197  elseif (aptap <= 0.0d0) then
198  ! A symmetric positive definite preconditioner must give {ap}^T[Minv]{ap} > 0 for nonzero {ap}.
200  exit
201  endif
202  alpha = rtar_old / aptap
203 
204  !C===
205  !C +--------------------------------+
206  !C | {x}= {x} + ALPHA*{p} |
207  !C | {rt}= {rt} - ALPHA*{ap} |
208  !C | {z}= {z} - ALPHA*{map} |
209  !C +--------------------------------+
210  !C===
211  call hecmw_axpy_r(nndof, alpha, ww(:,p), x)
212  call hecmw_axpy_r(nndof, -alpha, ww(:,ap), ww(:,rt))
213  call hecmw_axpy_r(nndof, -alpha, ww(:,map), ww(:,r))
214 
215  !C===
216  !C +------------------------------------+
217  !C | RESID_REC= ||{rt}|| / ||{b}|| |
218  !C +------------------------------------+
219  !C===
220  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,rt), ww(:,rt), dnrm2, tcomm)
221  resid_rec = dsqrt(dnrm2/bnrm2)
222 
223  !C===
224  !C +------------------------------------------------+
225  !C | Explicit residual RESID_TRUE for monitoring |
226  !C +------------------------------------------------+
227  !C===
228  ! Compute the explicit residual only for convergence monitoring.
229  ! Do not replace the recursive PCR residual or restart the search directions.
230  ! It is checked when the recursive residual reaches the tolerance, on a
231  ! periodic monitoring iteration, or at the maximum iteration count.
232  true_checked = .false.
233  if (resid_rec.le.tol .or. mod(iter,n_iter_check_true_r)==0 .or. iter.eq.maxit) then
234  ! WK reuses the AZ column, which is free until [A]{z} is formed below.
235  call hecmw_matresid(hecmesh, hecmat, x, b, ww(:,wk), tcomm)
236  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,wk), ww(:,wk), dnrm2_true, tcomm)
237  resid_true = dsqrt(dnrm2_true/bnrm2)
238  true_checked = .true.
239  endif
240 
241  ! Return/display value: the explicit residual on a monitoring iteration,
242  ! the recursive residual otherwise.
243  if (true_checked) then
244  resid = resid_true
245  else
246  resid = resid_rec
247  endif
248 
249  !C##### Iteration history output
250  if (my_rank.eq.0.and.iterlog.eq.1) write (*,'(i7, 1pe16.6)') iter, resid
251  !C#####
252 
253  if (true_checked) then
254  if (resid_true.le.tol) exit
255  if (iter.eq.maxit) then
257  exit
258  endif
259  endif
260 
261  !C===
262  !C +--------------------+
263  !C | {az}= [A]{z} |
264  !C +--------------------+
265  !C===
266  call hecmw_matvec(hecmesh, hecmat, ww(:,r), ww(:,az), tcomm)
267 
268  !C===
269  !C +-----------------------------+
270  !C | rTAr= {z}^T[A]{z} |
271  !C | BETA= rTAr / rTAr_old |
272  !C +-----------------------------+
273  !C===
274  call hecmw_innerproduct_r(hecmesh, ndof, ww(:,r), ww(:,az), rtar, tcomm)
275 
276  if (rtar /= rtar) then
278  exit
279  elseif (rtar <= 0.0d0) then
281  exit
282  endif
283 
284  beta = rtar / rtar_old
285  rtar_old = rtar
286 
287  !C===
288  !C +------------------------------+
289  !C | {p}= {z} + BETA*{p} |
290  !C | {ap}= {az} + BETA*{ap} |
291  !C +------------------------------+
292  !C===
293  call hecmw_xpay_r(nndof, beta, ww(:,r), ww(:,p))
294  call hecmw_xpay_r(nndof, beta, ww(:,az), ww(:,ap))
295 
296  enddo
297  if (maxit.eq.0) iter = 0
298  !C
299  !C*************************************************************** Iteration ends
300  !C
301 
302  call hecmw_solver_scaling_bk(hecmat)
303  !C
304  !C-- INTERFACE data EXCHANGE
305  !C
306  start_time = hecmw_wtime()
307  call hecmw_update_r(hecmesh, x, hecmat%NP, hecmat%NDOF)
308  end_time = hecmw_wtime()
309  tcomm = tcomm + end_time - start_time
310 
311  deallocate(ww)
312 
313  call hecmw_matvec_teardown(hecmat)
314  if (hecmw_mat_get_usejad(hecmat).ne.0) then
315  call hecmw_jad_finalize(hecmat)
316  endif
317 
318  e1_time = hecmw_wtime()
319  if (timelog.eq.2) then
320  call hecmw_time_statistics(hecmesh, e1_time - s1_time, t_max, t_min, t_avg, t_sd)
321  if (hecmesh%my_rank.eq.0) then
322  write(*,*) 'Time solver iterations'
323  write(*,*) ' Max :',t_max
324  write(*,*) ' Min :',t_min
325  write(*,*) ' Avg :',t_avg
326  write(*,*) ' Std Dev :',t_sd
327  endif
328  tsol = t_max
329  else
330  tsol = e1_time - s1_time
331  endif
332 
333  end subroutine hecmw_solve_cr
334 end module hecmw_solver_cr
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
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_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_cr(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