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