solpcg.F90 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. MODULE solpcg
  2. !!======================================================================
  3. !! *** MODULE solfet
  4. !! Ocean solver : preconditionned conjugate gradient solver
  5. !!=====================================================================
  6. !!----------------------------------------------------------------------
  7. !! sol_pcg : preconditionned conjugate gradient solver
  8. !!----------------------------------------------------------------------
  9. USE oce ! ocean dynamics and tracers variables
  10. USE dom_oce ! ocean space and time domain variables
  11. USE sol_oce ! ocean solver variables
  12. USE lib_mpp ! distributed memory computing
  13. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  14. USE in_out_manager ! I/O manager
  15. USE lib_fortran ! Fortran routines library
  16. USE wrk_nemo ! Memory allocation
  17. USE timing ! Timing
  18. IMPLICIT NONE
  19. PRIVATE
  20. PUBLIC sol_pcg !
  21. !! * Substitutions
  22. # include "vectopt_loop_substitute.h90"
  23. !!----------------------------------------------------------------------
  24. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  25. !! $Id: solpcg.F90 3294 2012-01-28 16:44:18Z rblod $
  26. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  27. !!----------------------------------------------------------------------
  28. CONTAINS
  29. SUBROUTINE sol_pcg( kindic )
  30. !!----------------------------------------------------------------------
  31. !! *** ROUTINE sol_pcg ***
  32. !!
  33. !! ** Purpose : Solve the ellipic equation for the transport
  34. !! divergence system using a diagonal preconditionned
  35. !! conjugate gradient method.
  36. !!
  37. !! ** Method : Diagonal preconditionned conjugate gradient method.
  38. !! the algorithm is multitasked. (case of 5 points matrix)
  39. !! define pa = q^-1 * a
  40. !! pgcb = q^-1 * gcb
  41. !! < . ; . >_q = ( . )^t q ( . )
  42. !! where q is the preconditioning matrix = diagonal matrix of the
  43. !! diagonal elements of a
  44. !! Initialization :
  45. !! x(o) = gcx
  46. !! r(o) = d(o) = pgcb - pa.x(o)
  47. !! rr(o)= < r(o) , r(o) >_q
  48. !! Iteration 1 :
  49. !! standard PCG algorithm
  50. !! Iteration n > 1 :
  51. !! s(n) = pa.r(n)
  52. !! gam(n) = < r(n) , r(n) >_q
  53. !! del(n) = < r(n) , s(n) >_q
  54. !! bet(n) = gam(n) / gam(n-1)
  55. !! d(n) = r(n) + bet(n) d(n-1)
  56. !! z(n) = s(n) + bet(n) z(n-1)
  57. !! sig(n) = del(n) - bet(n)*bet(n)*sig(n-1)
  58. !! alp(n) = gam(n) / sig(n)
  59. !! x(n+1) = x(n) + alp(n) d(n)
  60. !! r(n+1) = r(n) - alp(n) z(n)
  61. !! Convergence test :
  62. !! rr(n+1) / < gcb , gcb >_q =< epsr
  63. !!
  64. !! ** Action : - niter : solver number of iteration done
  65. !! - res : solver residu reached
  66. !! - gcx() : solution of the elliptic system
  67. !!
  68. !! References :
  69. !! Madec et al. 1988, Ocean Modelling, issue 78, 1-6.
  70. !! D Azevedo et al. 1993, Computer Science Technical Report, Tennessee U.
  71. !!
  72. !! History :
  73. !! ! 90-10 (G. Madec) Original code
  74. !! ! 91-11 (G. Madec)
  75. !! ! 93-04 (M. Guyon) loops and suppress pointers
  76. !! ! 95-09 (M. Imbard, J. Escobar) mpp exchange
  77. !! ! 96-05 (G. Madec) merge sor and pcg formulations
  78. !! ! 96-11 (A. Weaver) correction to preconditioning
  79. !! 8.5 ! 02-08 (G. Madec) F90: Free form
  80. !! ! 08-01 (R. Benshila) mpp optimization
  81. !!----------------------------------------------------------------------
  82. !!
  83. INTEGER, INTENT(inout) :: kindic ! solver indicator, < 0 if the conver-
  84. ! ! gence is not reached: the model is stopped in step
  85. ! ! set to zero before the call of solpcg
  86. !!
  87. INTEGER :: ji, jj, jn ! dummy loop indices
  88. REAL(wp) :: zgcad ! temporary scalars
  89. REAL(wp), DIMENSION(2) :: zsum
  90. REAL(wp), POINTER, DIMENSION(:,:) :: zgcr
  91. !!----------------------------------------------------------------------
  92. !
  93. IF( nn_timing == 1 ) CALL timing_start('sol_pcg')
  94. !
  95. CALL wrk_alloc( jpi, jpj, zgcr )
  96. !
  97. ! Initialization of the algorithm with standard PCG
  98. ! -------------------------------------------------
  99. zgcr = 0._wp
  100. gcr = 0._wp
  101. CALL lbc_lnk( gcx, c_solver_pt, 1. ) ! lateral boundary condition
  102. ! gcr = gcb-a.gcx
  103. ! gcdes = gcr
  104. DO jj = 2, jpjm1
  105. DO ji = fs_2, fs_jpim1 ! vector opt.
  106. zgcad = bmask(ji,jj) * ( gcb(ji,jj ) - gcx(ji ,jj ) &
  107. & - gcp(ji,jj,1) * gcx(ji ,jj-1) &
  108. & - gcp(ji,jj,2) * gcx(ji-1,jj ) &
  109. & - gcp(ji,jj,3) * gcx(ji+1,jj ) &
  110. & - gcp(ji,jj,4) * gcx(ji ,jj+1) )
  111. gcr (ji,jj) = zgcad
  112. gcdes(ji,jj) = zgcad
  113. END DO
  114. END DO
  115. ! rnorme = (gcr,gcr)
  116. rnorme = glob_sum( gcr(:,:) * gcdmat(:,:) * gcr(:,:) )
  117. CALL lbc_lnk( gcdes, c_solver_pt, 1. ) ! lateral boundary condition
  118. ! gccd = matrix . gcdes
  119. DO jj = 2, jpjm1
  120. DO ji = fs_2, fs_jpim1 ! vector opt.
  121. gccd(ji,jj) = bmask(ji,jj)*( gcdes(ji,jj) &
  122. & +gcp(ji,jj,1)*gcdes(ji,jj-1)+gcp(ji,jj,2)*gcdes(ji-1,jj) &
  123. & +gcp(ji,jj,4)*gcdes(ji,jj+1)+gcp(ji,jj,3)*gcdes(ji+1,jj) )
  124. END DO
  125. END DO
  126. ! alph = (gcr,gcr)/(gcdes,gccd)
  127. radd = glob_sum( gcdes(:,:) * gcdmat(:,:) * gccd(:,:) )
  128. alph = rnorme /radd
  129. ! gcx = gcx + alph * gcdes
  130. ! gcr = gcr - alph * gccd
  131. DO jj = 2, jpjm1
  132. DO ji = fs_2, fs_jpim1 ! vector opt.
  133. gcx(ji,jj) = bmask(ji,jj) * ( gcx(ji,jj) + alph * gcdes(ji,jj) )
  134. gcr(ji,jj) = bmask(ji,jj) * ( gcr(ji,jj) - alph * gccd (ji,jj) )
  135. END DO
  136. END DO
  137. ! Algorithm wtih Eijkhout rearrangement
  138. ! -------------------------------------
  139. ! !================
  140. DO jn = 1, nn_nmax ! Iterative loop
  141. ! !================
  142. CALL lbc_lnk( gcr, c_solver_pt, 1. ) ! lateral boundary condition
  143. ! zgcr = matrix . gcr
  144. DO jj = 2, jpjm1
  145. DO ji = fs_2, fs_jpim1 ! vector opt.
  146. zgcr(ji,jj) = bmask(ji,jj)*( gcr(ji,jj) &
  147. & +gcp(ji,jj,1)*gcr(ji,jj-1)+gcp(ji,jj,2)*gcr(ji-1,jj) &
  148. & +gcp(ji,jj,4)*gcr(ji,jj+1)+gcp(ji,jj,3)*gcr(ji+1,jj) )
  149. END DO
  150. END DO
  151. ! rnorme = (gcr,gcr)
  152. rr = rnorme
  153. ! zgcad = (zgcr,gcr)
  154. zsum(1) = glob_sum(gcr(:,:) * gcdmat(:,:) * gcr(:,:))
  155. zsum(2) = glob_sum(gcr(:,:) * gcdmat(:,:) * zgcr(:,:) * bmask(:,:))
  156. !!RB we should gather the 2 glob_sum
  157. rnorme = zsum(1)
  158. zgcad = zsum(2)
  159. ! test of convergence
  160. IF( rnorme < epsr .OR. jn == nn_nmax ) THEN
  161. res = SQRT( rnorme )
  162. niter = jn
  163. ncut = 999
  164. ENDIF
  165. ! beta = (rk+1,rk+1)/(rk,rk)
  166. beta = rnorme / rr
  167. radd = zgcad - beta*beta*radd
  168. alph = rnorme / radd
  169. ! gcx = gcx + alph * gcdes
  170. ! gcr = gcr - alph * gccd
  171. DO jj = 2, jpjm1
  172. DO ji = fs_2, fs_jpim1 ! vector opt.
  173. gcdes(ji,jj) = gcr (ji,jj) + beta * gcdes(ji,jj)
  174. gccd (ji,jj) = zgcr(ji,jj) + beta * gccd (ji,jj)
  175. gcx (ji,jj) = gcx (ji,jj) + alph * gcdes(ji,jj)
  176. gcr (ji,jj) = gcr (ji,jj) - alph * gccd (ji,jj)
  177. END DO
  178. END DO
  179. ! indicator of non-convergence or explosion
  180. IF( jn == nn_nmax .OR. SQRT(epsr)/eps > 1.e+20 ) kindic = -2
  181. IF( ncut == 999 ) GOTO 999
  182. ! !================
  183. END DO ! End Loop
  184. ! !================
  185. 999 CONTINUE
  186. CALL lbc_lnk( gcx, c_solver_pt, 1. ) ! Output in gcx with lateral b.c. applied
  187. !
  188. CALL wrk_dealloc( jpi, jpj, zgcr )
  189. !
  190. IF( nn_timing == 1 ) CALL timing_stop('sol_pcg')
  191. !
  192. END SUBROUTINE sol_pcg
  193. !!=====================================================================
  194. END MODULE solpcg