MFIX  2016-1
leq_bicgs.f
Go to the documentation of this file.
1 !vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvC
2 ! C
3 ! Subroutine LEQ_BICGS C
4 ! Purpose: Solve system of linear system using BICGS method C
5 ! Biconjugate gradients stabilized C
6 ! C
7 ! Author: Ed D'Azevedo Date: 21-JAN-99 C
8 ! Reviewer: Date: C
9 ! C
10 ! Literature/Document References: C
11 ! Variables referenced: C
12 ! Variables modified: C
13 ! Local variables: C
14 ! C
15 !^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^C
16 ! Handan Liu wrote below: !Jan 22 2013
17 ! The modification is as below:
18 ! Adding a loop of 2D RSRS sweep and parallelizing for OpenMP.
19 ! Splitting the existing 3D RSRS loop into two loops for OpenMP
20 ! due to data dependency
21 ! Adding openmp directives in all loops in leq_bicgs0.
22 !
23  SUBROUTINE leq_bicgs(VNAME, VNO, VAR, A_M, B_m, cmethod, &
24  tol, pc, itmax, ier)
25 
26 !-----------------------------------------------
27 ! Modules
28 !-----------------------------------------------
29  USE param
30  USE param1
31  USE geometry
32  USE compar
33  USE indices
34  USE leqsol
35  USE funits
36  IMPLICIT NONE
37 !-----------------------------------------------
38 ! Dummy arguments
39 !-----------------------------------------------
40 ! variable name
41  CHARACTER(LEN=*), INTENT(IN) :: Vname
42 ! variable number (not really used here; see calling subroutine)
43  INTEGER, INTENT(IN) :: VNO
44 ! variable
45 ! e.g., pp_g, epp, rop_g, rop_s, u_g, u_s, v_g, v_s, w_g,
46 ! w_s, T_g, T_s, x_g, x_s, Theta_m, scalar, K_Turb_G,
47 ! e_Turb_G
48 ! DOUBLE PRECISION, DIMENSION(ijkstart3:ijkend3), INTENT(INOUT) :: Var
49  DOUBLE PRECISION, DIMENSION(DIMENSION_3), INTENT(INOUT) :: Var
50 ! Septadiagonal matrix A_m
51 ! DOUBLE PRECISION, DIMENSION(ijkstart3:ijkend3,-3:3), INTENT(INOUT) :: A_m
52  DOUBLE PRECISION, DIMENSION(DIMENSION_3,-3:3), INTENT(INOUT) :: A_m
53 
54 ! Vector b_m
55 ! DOUBLE PRECISION, DIMENSION(ijkstart3:ijkend3), INTENT(INOUT) :: B_m
56  DOUBLE PRECISION, DIMENSION(DIMENSION_3), INTENT(INOUT) :: B_m
57 ! Sweep direction of leq solver (leq_sweep)
58 ! e.g., options = 'isis', 'rsrs' (default), 'asas'
59 ! Note: this setting only seems to matter when leq_pc='line'
60  CHARACTER(LEN=*), INTENT(IN) :: CMETHOD
61 ! convergence tolerance (generally leq_tol)
62  DOUBLE PRECISION, INTENT(IN) :: TOL
63 ! preconditioner (leq_pc)
64 ! options = 'line' (default), 'diag', 'none'
65  CHARACTER(LEN=4), INTENT(IN) :: PC
66 ! maximum number of iterations (generally leq_it)
67  INTEGER, INTENT(IN) :: ITMAX
68 ! error indicator
69  INTEGER, INTENT(INOUT) :: IER
70 !-------------------------------------------------
71 ! Local Variables
72 !-------------------------------------------------
73 
74  if(pc.eq.'LINE') then ! default
75  call leq_bicgs0( vname, vno, var, a_m, b_m, &
76  cmethod, tol, itmax, leq_matvec, leq_msolve, .true., ier )
77  elseif(pc.eq.'DIAG') then
78  call leq_bicgs0( vname, vno, var, a_m, b_m, &
79  cmethod, tol, itmax, leq_matvec, leq_msolve1, .true., ier )
80  elseif(pc.eq.'NONE') then
81  call leq_bicgs0( vname, vno, var, a_m, b_m, &
82  cmethod, tol, itmax, leq_matvec, leq_msolve0, .false., ier )
83  else
84  IF(dmp_log)WRITE (unit_log,*) &
85  'preconditioner option not found - check mfix.dat and readme'
86  call mfix_exit(mype)
87  endif
88 
89  return
90  END SUBROUTINE leq_bicgs
91 
92 !vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvC
93 ! C
94 ! Subroutine: LEQ_BICGS0 C
95 ! Purpose: Compute residual of linear system C
96 ! C
97 ! Author: Ed D'Azevedo Date: 21-JAN-99 C
98 ! Reviewer: Date: C
99 ! C
100 ! Literature/Document References: C
101 ! Variables referenced: C
102 ! Variables modified: C
103 ! Local variables: C
104 ! C
105 !^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^C
106 
107  SUBROUTINE leq_bicgs0(VNAME, VNO, VAR, A_M, B_m, cmethod, &
108  tol, itmax, matvec, msolve, use_pc, ier )
110 !-----------------------------------------------
111 ! Modules
112 !-----------------------------------------------
113  USE param
114  USE param1
115  USE geometry
116  USE compar
117  USE mpi_utility
118  USE sendrecv
119  USE indices
120  USE leqsol
121  USE cutcell
122  USE functions
123 
124  IMPLICIT NONE
125 !-----------------------------------------------
126 ! Dummy arguments/procedure
127 !-----------------------------------------------
128 ! variable name
129  CHARACTER(LEN=*), INTENT(IN) :: Vname
130 ! variable number (not really used here-see calling subroutine)
131  INTEGER, INTENT(IN) :: VNO
132 ! variable
133 ! e.g., pp_g, epp, rop_g, rop_s, u_g, u_s, v_g, v_s, w_g,
134 ! w_s, T_g, T_s, x_g, x_s, Theta_m, scalar, K_Turb_G,
135 ! e_Turb_G
136 ! DOUBLE PRECISION, INTENT(INOUT) :: Var(ijkstart3:ijkend3)
137  DOUBLE PRECISION, DIMENSION(DIMENSION_3), INTENT(INOUT) :: Var
138 ! Septadiagonal matrix A_m
139 ! DOUBLE PRECISION, INTENT(INOUT) :: A_m(ijkstart3:ijkend3,-3:3)
140  DOUBLE PRECISION, DIMENSION(DIMENSION_3,-3:3), INTENT(INOUT) :: A_m
141 ! Vector b_m
142 ! DOUBLE PRECISION, INTENT(INOUT) :: B_m(ijkstart3:ijkend3)
143  DOUBLE PRECISION, DIMENSION(DIMENSION_3), INTENT(INOUT) :: B_m
144 ! Sweep direction of leq solver (leq_sweep)
145 ! e.g., options = 'isis', 'rsrs' (default), 'asas'
146  CHARACTER(LEN=*), INTENT(IN) :: CMETHOD
147 ! convergence tolerance (generally leq_tol)
148  DOUBLE PRECISION, INTENT(IN) :: TOL
149 ! maximum number of iterations (generally leq_it)
150  INTEGER, INTENT(IN) :: ITMAX
151 ! indicate whether to use preconditioner
152  LOGICAL, INTENT(IN) :: USE_PC
153 ! error indicator
154  INTEGER, INTENT(INOUT) :: IER
155 ! dummy arguments/procedures set as indicated
156 ! matvec->leq_matvec
157 ! for preconditioner (leq_pc)
158 ! 'line' msolve->leq_msolve (default)
159 ! 'diag' msolve->leq_msolve1
160 ! 'none' msolve->leq_msolve0
161 !-----------------------------------------------
162 ! Local parameters
163 !-----------------------------------------------
164  INTEGER, PARAMETER :: idebugl = 0
165  DOUBLE PRECISION, PARAMETER :: ratiotol = 0.2
166  LOGICAL, PARAMETER :: do_unit_scaling = .true.
167 !-----------------------------------------------
168 ! Local variables
169 !-----------------------------------------------
170 
171  DOUBLE PRECISION, DIMENSION(:), allocatable :: R,Rtilde, Tvec,V
172  DOUBLE PRECISION, DIMENSION(:), allocatable, target :: P, P_preconditioned
173  DOUBLE PRECISION, DIMENSION(:), allocatable, target :: Svec, Svec_preconditioned
174 
175  ! Phat points to either preconditioned value of P, or P itself (to avoid copying for efficiency)
176  DOUBLE PRECISION, POINTER :: Phat(:), Shat(:)
177 
178  DOUBLE PRECISION, DIMENSION(0:ITMAX+1) :: &
179  alpha, beta, omega, rho
180  DOUBLE PRECISION :: TxS, TxT, RtildexV, &
181  aijmax, oam
182  DOUBLE PRECISION :: Rnorm, Rnorm0, Snorm, TOLMIN, pnorm
183  LOGICAL :: isconverged
184  INTEGER :: i, j, k, ijk
185  INTEGER :: iter
186  DOUBLE PRECISION, DIMENSION(2) :: TxS_TxT
187 !-----------------------------------------------
188 
189 ! Initialize the error flag.
190  ier=0
191 
192 ! Scale matrix to have unit diagonal
193 ! ---------------------------------------------------------------->>>
194  if (do_unit_scaling) then
195 
196  IF(re_indexing) THEN ! Loop only over active cells
197 !$omp parallel do default(shared) private(ijk,oam,aijmax)
198  DO ijk = ijkstart3,ijkend3
199  aijmax = maxval(abs(a_m(ijk,:)) )
200  if (aijmax > 0.0)then
201  oam = one/aijmax
202  a_m(ijk,:) = a_m(ijk,:)*oam
203  b_m(ijk) = b_m(ijk)*oam
204  else
205  ier = -2
206  endif
207  ENDDO
208 
209  ELSE
210 
211 !$omp parallel do default(shared) private(ijk,i,j,k,oam,aijmax)
212  do k = kstart2,kend2
213  do i = istart2,iend2
214  do j = jstart2,jend2
215  ijk = funijk(i,j,k)
216  aijmax = maxval(abs(a_m(ijk,:)) )
217  if (aijmax > 0.0) then
218  oam = one/aijmax
219  a_m(ijk,:) = a_m(ijk,:)*oam
220  b_m(ijk) = b_m(ijk)*oam
221  else
222  ier = -2
223  endif
224  enddo
225  enddo
226  enddo
227 
228  ENDIF
229 
230  endif
231 
232 ! A singlular matrix was detected.
233  if(ier /= 0) RETURN
234 ! ----------------------------------------------------------------<<<
235 
236 
237 
238  allocate(r(dimension_3))
239  allocate(rtilde(dimension_3))
240  allocate(p(dimension_3))
241  allocate(p_preconditioned(dimension_3))
242  allocate(svec(dimension_3))
243  allocate(svec_preconditioned(dimension_3))
244  allocate(tvec(dimension_3))
245  allocate(v(dimension_3))
246 
247 ! these scalars should not be necessary to initialize but done as failsafe
248  rnorm = zero
249  rnorm0 = zero
250  snorm = zero
251  pnorm = zero
252 
253 ! initializing
254  alpha(:) = zero
255  beta(:) = zero
256  omega(:) = zero
257  rho(:) = zero
258 
259 !$omp parallel sections
260  r(:) = zero
261 !$omp section
262  rtilde(:) = zero
263 !$omp section
264  p(:) = zero
265 !$omp section
266  p_preconditioned(:) = zero
267 !$omp section
268  svec(:) = zero
269 !$omp section
270  svec_preconditioned(:) = zero
271 !$omp section
272  tvec(:) = zero
273 !$omp section
274  v(:) = zero
275 !$omp end parallel sections
276 
277  tolmin = epsilon( one )
278 
279 ! Compute initial residual (R = b-A*x) for Ax=b
280 ! assume initial guess in Var
281 ! rtilde = r
282 ! ---------------------------------------------------------------->>>
283  call matvec(vname, var, a_m, r) ! returns R=A*Var
284 
285 !$omp parallel workshare
286  r(:) = b_m(:) - r(:)
287 !$omp end parallel workshare
288 
289  call send_recv(r,nlayers_bicgs)
290 
291  rnorm0 = sqrt( dot_product_par( r, r ) )
292 
293 ! determine an initial guess for the residual = residual + small random
294 ! number (so it could be set to anything). note that since random_number
295 ! is used to supply the guess, this line could potentially be the source
296 ! of small differences between runs. the random number is shifted below
297 ! between -1 and 1 and then scaled by factor 1.0D-6*Rnorm0
298  call random_number(rtilde(:))
299 
300 ! Shift random number array to be consistent with case when RE_INDEXING is .FALSE.
301  IF(re_indexing) CALL shift_dp_array(rtilde)
302 
303 !$omp parallel workshare
304  rtilde(:) = r(:) + (2.0d0*rtilde(:)-1.0d0)*1.0d-6*rnorm0
305 !$omp end parallel workshare
306 
307  if (idebugl >= 1) then
308  if(mype.eq.0) print*,'leq_bicgs, initial: ', vname,' resid ', rnorm0
309  endif
310 ! ----------------------------------------------------------------<<<
311 
312 
313 ! Main loop
314 ! ---------------------------------------------------------------->>>
315  iter = 1
316  do i=1,itmax
317 
318  rho(i-1) = dot_product_par( rtilde, r )
319 
320  if (rho(i-1) .eq. zero) then
321  if(i /= 1)then
322 ! Method fails
323 ! --------------------------------
324  ier = -2
325  else
326 ! Method converged. residual is already zero
327 ! --------------------------------
328  ier = 0
329  endif
330  call send_recv(var,2)
331  return
332  endif ! rho(i-1).eq.0
333 
334  if (i .eq. 1) then
335 !$omp parallel workshare
336  p(:) = r(:)
337 !$omp end parallel workshare
338  else
339  beta(i-1) = ( rho(i-1)/rho(i-2) )*( alpha(i-1) / omega(i-1) )
340 !$omp parallel workshare
341  p(:) = r(:) + beta(i-1)*( p(:) - omega(i-1)*v(:) )
342 !$omp end parallel workshare
343  endif ! i.eq.1
344 
345 ! Solve A*Phat(:) = P(:)
346 ! V(:) = A*Phat(:)
347 ! --------------------------------
348  if (use_pc) then
349  call msolve(vname, p, a_m, p_preconditioned, cmethod) ! returns P_preconditioned
350  phat => p_preconditioned
351  else
352  phat => p
353  endif
354 
355  call matvec(vname, phat, a_m, v) ! returns V=A*Phat
356 
357  rtildexv = dot_product_par( rtilde, v )
358 
359 ! compute alpha
360 ! --------------------------------
361  alpha(i) = rho(i-1) / rtildexv
362 
363 ! compute Svec
364 ! --------------------------------
365 !$omp parallel workshare
366  svec(:) = r(:) - alpha(i) * v(:)
367 !$omp end parallel workshare
368 
369 ! Check norm of Svec(:); if small enough:
370 ! set X(:) = X(:) + alpha(i)*Phat(:) and stop
371 ! --------------------------------
372  if(.not.minimize_dotproducts) then
373  snorm = sqrt( dot_product_par( svec, svec ) )
374 
375  if (snorm <= tolmin) then
376 !$omp parallel workshare
377  var(:) = var(:) + alpha(i)*phat(:)
378 !$omp end parallel workshare
379 
380 ! Recompute residual norm
381 ! --------------------------------
382  if (idebugl >= 1) then
383  call matvec(vname, var, a_m, r) ! returns R=A*Var
384 ! Rnorm = sqrt( dot_product_par( Var, Var ) )
385 ! print*,'leq_bicgs, initial: ', Vname,' Vnorm ', Rnorm
386 
387 !$omp parallel workshare
388  r(:) = b_m(:) - r(:)
389 !$omp end parallel workshare
390 
391  rnorm = sqrt( dot_product_par( r, r ) )
392  endif ! idebugl >= 1
393  isconverged = .true.
394  EXIT
395  endif ! end if (Snorm <= TOLMIN)
396  endif ! end if (.not.minimize_dotproducts)
397 
398 ! Solve A*Shat(:) = Svec(:)
399 ! Tvec(:) = A*Shat(:)
400 ! --------------------------------
401 
402  if (use_pc) then
403  call msolve(vname, svec, a_m, svec_preconditioned, cmethod) ! returns S_preconditioned
404  shat => svec_preconditioned
405  else
406  shat => svec
407  endif
408 
409  call matvec( vname, shat, a_m, tvec ) ! returns Tvec=A*Shat
410 
411  if(.not.minimize_dotproducts) then
412 !! $omp parallel sections
413  txs = dot_product_par( tvec, svec )
414 !! $omp section
415  txt = dot_product_par( tvec, tvec )
416 !! $omp end parallel sections
417  else
418  txs_txt = dot_product_par2(tvec, svec, tvec, tvec )
419  txs = txs_txt(1)
420  txt = txs_txt(2)
421  endif
422 
423  IF(txt.eq.zero) txt = small_number
424 
425 ! compute omega
426 ! --------------------------------
427  omega(i) = txs / txt
428 
429 ! compute new guess for Var
430 ! --------------------------------
431 
432 !$omp parallel sections
433  var(:) = var(:) + alpha(i)*phat(:) + omega(i)*shat(:)
434 !$omp section
435  r(:) = svec(:) - omega(i)*tvec(:)
436 !$omp end parallel sections
437 
438 ! --------------------------------
439  if(.not.minimize_dotproducts.or.(mod(iter,icheck_bicgs).eq.0)) then
440  rnorm = sqrt( dot_product_par(r, r) )
441 
442  if (idebugl.ge.1) then
443  if (mype.eq.pe_io) then
444  print*,'iter, Rnorm ', iter, rnorm, snorm
445  print*,'alpha(i), omega(i) ', alpha(i), omega(i)
446  print*,'TxS, TxT ', txs, txt
447  print*,'RtildexV, rho(i-1) ', rtildexv, rho(i-1)
448  endif
449  endif
450 
451 ! call mfix_exit(myPE)
452 
453 ! Check convergence; continue if necessary
454 ! for continuation, it is necessary that omega(i) .ne. 0
455  isconverged = (rnorm <= tol*rnorm0)
456 
457  if (isconverged) then
458  iter_tot(vno) = iter_tot(vno) + iter + 1
459  EXIT
460  endif
461  endif ! end if(.not.minimize_dotproducts)
462 
463 ! Advance the iteration count
464  iter = iter + 1
465 
466  enddo ! end do i=1,itmax
467 ! end of linear solver loop
468 ! ----------------------------------------------------------------<<<
469 
470  if (idebugl >= 1) then
471  call matvec(vname, var, a_m, r) ! returns R=A*Var
472 
473 !$omp parallel workshare
474  r(:) = r(:) - b_m(:)
475 !$omp end parallel workshare
476 
477  rnorm = sqrt( dot_product_par( r,r) )
478 
479  if(mype.eq.0) print*,'leq_bicgs: final Rnorm ', rnorm
480 
481  if(mype.eq.0) print*,'leq_bicgs ratio : ', vname,' ',iter, &
482  ' L-2', rnorm/rnorm0
483  endif ! end if(idebugl >=1)
484 
485 ! isconverged = (real(Rnorm) <= TOL*Rnorm0);
486  if(.NOT.isconverged) isconverged = (real(Rnorm) <= tol*rnorm0);
487 ! write(*,*) '***',iter, isconverged, Rnorm, TOL, Rnorm0, myPE
488  ier = 0
489  if (.not.isconverged) then
490  ier = -1
491  iter_tot(vno) = iter_tot(vno) + iter
492  if (real(Rnorm) >= ratiotol*real(rnorm0)) then
493  ier = -2
494  endif
495  endif
496 
497  call send_recv(var,2)
498 
499  deallocate(r)
500  deallocate(rtilde)
501  deallocate(p)
502  deallocate(p_preconditioned)
503  deallocate(svec)
504  deallocate(svec_preconditioned)
505  deallocate(tvec)
506  deallocate(v)
507 
508  return
509  end subroutine leq_bicgs0
integer jend2
Definition: compar_mod.f:80
logical re_indexing
Definition: cutcell_mod.f:16
logical dmp_log
Definition: funits_mod.f:6
integer nlayers_bicgs
Definition: compar_mod.f:45
integer ijkend3
Definition: compar_mod.f:80
subroutine leq_matvec(VNAME, VAR, A_M, Avar)
Definition: leqsol_mod.f:104
integer icheck_bicgs
Definition: leqsol_mod.f:35
double precision, parameter one
Definition: param1_mod.f:29
integer dimension_3
Definition: param_mod.f:11
integer istart2
Definition: compar_mod.f:80
integer, dimension(dim_eqs) iter_tot
Definition: leqsol_mod.f:17
integer iend2
Definition: compar_mod.f:80
subroutine leq_msolve(VNAME, B_m, A_M, Var, CMETHOD)
Definition: leqsol_mod.f:287
integer kend2
Definition: compar_mod.f:80
integer kstart2
Definition: compar_mod.f:80
subroutine shift_dp_array(ARRAY)
subroutine leq_msolve0(VNAME, B_m, A_M, Var, CMETHOD)
Definition: leqsol_mod.f:617
integer pe_io
Definition: compar_mod.f:30
double precision function dot_product_par(r1, r2)
Definition: leqsol_mod.f:1095
double precision, parameter small_number
Definition: param1_mod.f:24
integer jstart2
Definition: compar_mod.f:80
double precision function, dimension(2) dot_product_par2(r1, r2, r3, r4)
Definition: leqsol_mod.f:1211
integer, parameter unit_log
Definition: funits_mod.f:21
Definition: param_mod.f:2
subroutine leq_msolve1(VNAME, B_m, A_M, Var, CMETHOD)
Definition: leqsol_mod.f:682
logical minimize_dotproducts
Definition: leqsol_mod.f:29
integer mype
Definition: compar_mod.f:24
integer ijkstart3
Definition: compar_mod.f:80
double precision, parameter zero
Definition: param1_mod.f:27
subroutine leq_bicgs0(VNAME, VNO, VAR, A_M, B_m, cmethod, TOL, ITMAX, MATVEC, MSOLVE, USE_PC, IER)
Definition: leq_bicgs.f:109
subroutine leq_bicgs(VNAME, VNO, VAR, A_M, B_m, cmethod, TOL, PC, ITMAX, IER)
Definition: leq_bicgs.f:25