source: src/solvers/pcg.F90 @ 60e3a65

Revision 60e3a65, 29.5 KB checked in by Oleg Batrashev <ogbash@…>, 2 years ago (diff)

Clean code and factor out mesh plotting routines.

  • Property mode set to 100644
Line 
1! DOUG - Domain decomposition On Unstructured Grids
2! Copyright (C) 1998-2006 Faculty of Computer Science, University of Tartu and
3! Department of Mathematics, University of Bath
4!
5! This library is free software; you can redistribute it and/or
6! modify it under the terms of the GNU Lesser General Public
7! License as published by the Free Software Foundation; either
8! version 2.1 of the License, or (at your option) any later version.
9!
10! This library is distributed in the hope that it will be useful,
11! but WITHOUT ANY WARRANTY; without even the implied warranty of
12! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13! Lesser General Public License for more details.
14!
15! You should have received a copy of the GNU Lesser General Public
16! License along with this library; if not, write to the Free Software
17! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18! or contact the authors (University of Tartu, Faculty of Computer Science, Chair
19! of Distributed Systems, Liivi 2, 50409 Tartu, Estonia, http://dougdevel.org,
20! mailto:info(at)dougdevel.org)
21
22!!----------------------------------
23!! Preconditioned Conjugate Gradient
24!!----------------------------------
25module pcg_mod
26
27  use ConvInf_mod
28  use SpMtx_mods
29  use Mesh_class
30  use globals
31  use subsolvers
32  use subsolvers_mult
33
34  implicit none
35
36#include<doug_config.h>
37
38#ifdef D_COMPLEX
39#define float complex
40#else
41#define float real
42#endif
43
44  integer,save :: coarseid=0
45  private :: &
46       preconditioner, &
47       msolve
48
49  ! profiling
50  real(kind=rk), private, save :: time_preconditioner = 0
51
52contains
53
54  !--------------------------------------------
55  ! Preconditioned conjugate gradient method
56  !--------------------------------------------
57  subroutine pcg (A, b, x, Msh, tol_, maxit_, &
58       x0_, solinf, resvects_, CoarseMtx_)
59    implicit none
60
61    type(SpMtx),intent(in out) :: A ! System matrix (sparse)
62    float(kind=rk),dimension(:),pointer :: b ! RHS
63    float(kind=rk),dimension(:),pointer :: x ! Solution
64    ! Mesh - aux data for Ax operation
65    type(Mesh),                       intent(in) :: Msh
66
67    ! Optional arguments
68    ! Tolerance of the method
69    real(kind=rk),          intent(in), optional :: tol_
70    ! Max number of iterations
71    integer,                intent(in), optional :: maxit_
72    ! Initial guess
73    float(kind=rk), dimension(:), intent(in), optional :: x0_
74    ! Solution statistics
75    type(ConvInf),            intent(in out), optional :: solinf
76    ! Fill in the 'resvect' or not
77    logical,                      intent(in), optional :: resvects_
78    type(SpMtx),optional                         :: CoarseMtx_ ! Coarse matrix
79
80    real(kind=rk) :: tol   ! Tolerance
81    integer       :: maxit ! Max number of iterations
82    logical       :: resvects=.false.
83
84    !real(kind=rk), dimension(size(b)) :: r, p, q, m, z, b_k
85    real(kind=rk),dimension(:),pointer :: r, p, q, m, z, b_k
86    real(kind=rk) :: rho_curr, rho_prev, init_norm, res_norm
87    real(kind=rk) :: alpha, beta, tmp, ratio_norm
88    integer :: iter,nfreds
89    integer :: ierr
90    ! + test
91    float(kind=rk), dimension(:), pointer :: arr_copy, gv_tmp
92
93!!$    real(kind=rk) :: r_max
94
95    write(stream,'(/a)') 'Preconditioned conjugate gradient:'
96
97    if (size(b) /= size(x)) &
98         call DOUG_abort('[pcg] : SEVERE : size(b) /= size(x)',-1)
99
100!!$    if (present(x0_))
101!!$         ! use method with initial guess
102
103
104    nfreds=size(b)
105    allocate(r(nfreds))
106    allocate(p(nfreds))
107    allocate(q(nfreds))
108    allocate(m(nfreds))
109    allocate(z(nfreds))
110    allocate(b_k(nfreds))
111
112
113    tol = sctls%solve_tolerance
114    if (present(tol_)) &
115         tol = tol_
116
117    maxit = sctls%solve_maxiters
118    if (maxit==-1) maxit=100000
119    if (present(maxit_)) &
120         maxit = maxit_
121
122    if (present(resvects_).and.(.not.present(solinf))) &
123         call DOUG_abort('[pcg] : SEVERE : "resvects_" must be given along'//&
124         ' with "solinf".',-1)
125
126    ! Allocate convergence info structure
127    if (present(solinf).and.(.not.present(resvects_))) then
128       call ConvInf_Init(solinf)
129    else if (present(solinf)) then
130       if (present(resvects_).and.(resvects_.eqv.(.true.))) then
131         call ConvInf_Init(solinf, maxit)
132         resvects = .true.
133       end if
134    end if
135
136    ! Initialise auxiliary data structures
137    ! to assist with pmvm
138    call pmvmCommStructs_init(A, Msh)
139
140    ! + test
141    if (ismaster()) &
142         allocate(gv_tmp(Msh%ngf))
143    allocate(arr_copy(Msh%nlf))
144
145    ! Build preconditioner
146    !  call preconditioner(A, m, CoarseMtx_)
147!!$    ! + test
148!!$    arr_copy = m
149!!$    call Vect_newToOldPerm(arr_copy)
150!!$    gv_tmp = 0.0_rk
151!!$    call Vect_Gather(arr_copy, gv_tmp, Msh)
152!!$    if (ismaster()) &
153!!$         call Vect_Print(gv_tmp, 'm ::')
154
155!!$    ! + test
156!!$    !b = 1.0_rk
157!!$    arr_copy = b
158!!$    call Vect_newToOldPerm(arr_copy)
159!!$    call Vect_Print(arr_copy, 'b local (original ordering) ::')
160!!$    gv_tmp = 0.0_rk
161!!$    call Vect_Gather(arr_copy, gv_tmp, Msh)
162!!$    if (ismaster()) &
163!!$         call Vect_Print(gv_tmp, 'b global (original ordering) ::')
164
165!!$    ! + test
166!!$    arr_copy = x
167!!$    call Vect_newToOldPerm(arr_copy)
168!!$    call Vect_Print(arr_copy, 'x local (original ordering) ::')
169!!$    gv_tmp = 0.0_rk
170!!$    call Vect_Gather(arr_copy, gv_tmp, Msh)
171!!$    if (ismaster()) &
172!!$         call Vect_Print(gv_tmp, 'x global (original ordering) ::')
173
174    !r = b - SpMtx_pmvm(A, x, Msh)
175    call SpMtx_pmvm(r,A,x,Msh)
176    r = b - r
177    !call Vect_Print(r,'initial residual')
178
179    ! + test
180!!$    arr_copy = r
181!!$    call Vect_newToOldPerm(arr_copy)
182!!$    gv_tmp = 0.0_rk
183!!$    call Vect_Gather(arr_copy, gv_tmp, Msh)
184!!$    if (ismaster()) &
185!!$         call Vect_Print(gv_tmp, 'r ::')
186
187    init_norm = Vect_dot_product(r,r)
188    if (init_norm == 0.0) &
189         init_norm = 1.0
190
191    write(stream,'(a,i6,a,e8.2)') 'maxit = ',maxit,', tol = ',tol
192    write(stream,'(a,e22.15)') 'init_norm = ', dsqrt(init_norm)
193
194    iter = 1
195    ratio_norm = 1.0_rk
196    do while((ratio_norm > tol*tol).and.(iter <= maxit))
197       call msolve(m,r,z)
198       !if (present(CoarseMtx_)) then
199       !  call preconditioner(z,A,r,CoarseMtx_)
200       !  !z=r
201       !else
202       !  call preconditioner(z,A,r)
203       !endif
204
205       !call Vect_Print(z,'preconditioner')
206
207       ! compute current rho
208       rho_curr = Vect_dot_product(r,z)
209       if (iter == 1) then
210          p = z
211       else
212          beta = rho_curr / rho_prev
213          p = z + beta * p
214       end if
215       !q = SpMtx_pmvm(A, p, Msh)
216       call SpMtx_pmvm(q,A,p,Msh)
217       ! compute alpha
218       alpha = rho_curr / Vect_dot_product(p,q)
219       x = x + alpha * p
220       r = r - alpha * q
221       rho_prev = rho_curr
222       ! check
223       res_norm = Vect_dot_product(r,r)
224       ratio_norm = dsqrt(res_norm) / dsqrt(init_norm)
225!!$       ratio_norm = res_norm / init_norm
226       if (ismaster()) &
227            write(stream, '(i5,a,e22.15)') iter,': res_norm=',dsqrt(res_norm)
228            !write(stream, '(i5,a,e22.15,e22.15)') iter,': dsqrt(ratio_norm)=',&
229            !dsqrt(ratio_norm), dsqrt(res_norm)
230       iter = iter + 1
231    end do
232
233    ! Deallocate auxiliary data structures
234    ! helped to assist with pmvm
235    call pmvmCommStructs_destroy()
236
237    deallocate(b_k)
238    deallocate(z)
239    deallocate(m)
240    deallocate(q)
241    deallocate(p)
242    deallocate(r)
243    if (associated(gv_tmp)) deallocate(gv_tmp)
244    if (associated(arr_copy)) deallocate(arr_copy)
245  end subroutine pcg
246
247  subroutine prec1Level(sol,A,rhs,M,res,A_interf_,CoarseMtx_,Restrict,refactor_)
248    implicit none
249    real(kind=rk),dimension(:),pointer :: sol !< solution
250    type(SpMtx)                        :: A   !< sparse system matrix
251    real(kind=rk),dimension(:),pointer :: rhs !< right hand side
252    type(Mesh),intent(in)              :: M   !< Mesh
253    real(kind=rk),dimension(:),pointer :: res !< residual vector, allocated
254                                              !! here for multiplicative Schwarz
255    type(SpMtx),optional               :: A_interf_  !< matr@interf.
256    type(SpMtx),optional               :: CoarseMtx_ !< Coarse matrix
257    type(SpMtx),optional               :: Restrict   !< Restriction matrix
258     logical,intent(inout),optional :: refactor_
259
260    type(SpMtx)                        :: A_tmp
261
262    if(sctls%method==1) then
263      if (refactor_) then!{
264        if (.not.present(CoarseMtx_).or.sctls%input_type==DCTL_INPUT_TYPE_ELEMENTAL.or.numprocs>1) then
265          call Factorise_subdomains(A,A_interf_)
266        else
267          if (.not.present(Restrict)) call DOUG_abort("Restriction matrix needs to be passed along with the coarse matrix!")
268          call Factorise_subdomains(A,AC=CoarseMtx_)
269        end if
270        refactor_=.false.
271      end if
272      call solve_subdomains(sol,A,rhs)
273
274    else if (sctls%method>1) then ! For multiplicative Schwarz method...:
275      if (numprocs>1) call DOUG_abort('multiplicative Schwarz only for numprocs==1 so far',-1)
276      if (.not.present(CoarseMtx_).or.sctls%input_type==DCTL_INPUT_TYPE_ELEMENTAL) then
277        call multiplicative_sparse_multisolve(sol=sol,A=A,M=M,rhs=rhs,res=res, &
278                          A_interf_=A_interf_, &
279                          refactor=refactor_) !fine solves
280      else
281        if (.not.present(Restrict)) call DOUG_abort("Restriction matrix needs to be passed along with the coarse matrix!")
282        call multiplicative_sparse_multisolve(sol=sol,A=A,M=M,rhs=rhs,res=res, &
283                          A_interf_=A_interf_,AC=CoarseMtx_, &
284                          refactor=refactor_,Restrict=Restrict) !fine solves
285      end if
286      refactor_=.false.
287    endif
288  end subroutine prec1Level
289
290  subroutine prec2Level(prepare,A,sol,rhs,res,CoarseMtx_,Restrict,isFirstIter)
291    use CoarseAllgathers
292
293    logical, intent(in) :: prepare
294    type(SpMtx)  :: A   !< sparse system matrix
295    real(kind=rk),dimension(:),pointer :: sol !< solution
296    real(kind=rk),dimension(:),pointer :: rhs !< right hand side
297    real(kind=rk),dimension(:),pointer :: res !< residual vector
298    type(SpMtx) :: CoarseMtx_ !< Coarse matrix
299    type(SpMtx) :: Restrict   !< Restriction matrix
300    logical :: isFirstIter
301
302    real(kind=rk),dimension(:),pointer,save :: csol,crhs,clrhs,tmpsol2,tmpsol
303    integer :: ol
304
305    ol=max(sctls%overlap,sctls%smoothers)
306
307    if (prepare) then
308      call prec2Level_prepare()
309    else
310      call prec2Level_solve()
311    end if
312 
313  contains
314    subroutine prec2Level_exchangeMatrix()
315      integer :: ol
316      logical :: add
317
318      ol=max(sctls%overlap,sctls%smoothers)
319      if (ol==0) then
320        add=.false.
321      else
322        add=.true.
323      endif
324
325      call AllSendCoarseMtx(cdat%LAC,CoarseMtx_,cdat%lg_cfmap,&
326           cdat%ngfc,cdat%nprocs,cdat%send)
327      call AllRecvCoarseMtx(CoarseMtx_,cdat%send,add=add) ! Recieve it
328
329    end subroutine prec2Level_exchangeMatrix
330
331    subroutine prec2Level_prepare()
332      if (isFirstIter) then
333        if (cdat%active) then
334          ! First iteration - send matrix
335          call prec2Level_exchangeMatrix()
336        end if
337
338        ! after coarse matrix is received allocate coarse vectors
339        if (associated(crhs)) then
340          if (size(crhs)/=CoarseMtx_%ncols) then
341            deallocate(csol)
342            deallocate(crhs)
343            allocate(crhs(CoarseMtx_%ncols))
344            allocate(csol(CoarseMtx_%nrows))
345          endif
346        else
347          allocate(crhs(CoarseMtx_%ncols))
348          allocate(csol(CoarseMtx_%nrows))
349        endif
350        write(stream,*) "Restrict%nrows", Restrict%nrows
351        allocate(clrhs(Restrict%nrows)) ! allocate memory for vector
352      end if
353
354      if (.not.associated(tmpsol)) then
355        !allocate(tmpsol(A%nrows))
356        allocate(tmpsol(size(rhs)))
357      endif
358
359      if (cdat%active) then
360        ! Send coarse vector
361        call SpMtx_Ax(clrhs,Restrict,rhs,dozero=.true.) ! restrict <RA>
362        if (cdat_vec%active) then
363          call AllSendCoarseVector(clrhs,cdat_vec%nprocs,cdat_vec%cdisps,&
364               cdat_vec%send,useprev=.not.isFirstIter)
365        else
366          call AllSendCoarseVector(clrhs,cdat%nprocs,cdat%cdisps,&
367               cdat%send,useprev=.not.isFirstIter)
368        endif
369      end if ! cdat%active
370    end subroutine prec2Level_prepare
371
372    subroutine prec2Level_solve()
373      if (.not.cdat%active) then ! 1 processor case
374        if (sctls%smoothers==-1) then
375          allocate(tmpsol2(A%nrows))
376          tmpsol2=0.0_rk
377          call exact_sparse_multismoother(tmpsol2,A,rhs)
378          call SpMtx_Ax(crhs,Restrict,tmpsol2,dozero=.true.) ! restriction
379        else
380          if (sctls%method>1.and.sctls%method/=5) then ! multiplicative Schwarz
381            call SpMtx_Ax(crhs,Restrict,res,dozero=.true.) ! restriction
382          else
383            call SpMtx_Ax(crhs,Restrict,rhs,dozero=.true.) ! restriction
384          endif
385        endif
386      end if
387
388      !csol=0.0_rk
389      if (cdat%active) then
390        ! Recieve the vector for solve
391        if (cdat_vec%active) then
392          call AllRecvCoarseVector(crhs,cdat_vec%nprocs,&
393               cdat_vec%cdisps,cdat_vec%glg_cfmap,cdat_vec%send)
394        else
395          call AllRecvCoarseVector(crhs,cdat%nprocs,&
396               cdat%cdisps,cdat%glg_cfmap,cdat%send)
397        endif
398        !call MPI_BARRIER(MPI_COMM_WORLD,i)
399      end if
400
401      if (isFirstIter) then
402        write (stream,*) &
403             'factorising coarse matrix of size',CoarseMtx_%nrows, &
404             ' and nnz:',CoarseMtx_%nnz
405        call free_spmtx_subsolves(CoarseMtx_)
406        allocate(CoarseMtx_%DD%subsolve_ids(1))
407        CoarseMtx_%DD%subsolve_ids=0
408        CoarseMtx_%DD%nsubsolves=1
409      end if
410
411      ! Coarse solve
412      call sparse_singlesolve(CoarseMtx_%DD%subsolve_ids(1),csol,crhs,&
413           nfreds=CoarseMtx_%nrows, &
414           nnz=CoarseMtx_%nnz,        &
415           indi=CoarseMtx_%indi,      &
416           indj=CoarseMtx_%indj,      &
417           val=CoarseMtx_%val)
418      if (isFirstIter) then
419        CoarseMtx_%indi=CoarseMtx_%indi+1
420        CoarseMtx_%indj=CoarseMtx_%indj+1
421      end if
422
423      if (cdat_vec%active) then
424        call Vect_remap(csol,clrhs,cdat_vec%gl_cfmap,dozero=.true.)
425        call SpMtx_Ax(tmpsol,Restrict,clrhs,dozero=.true.,transp=.true.)
426        !write(stream,*) "tmpsol", tmpsol
427      elseif (cdat%active) then
428        call Vect_remap(csol,clrhs,cdat%gl_cfmap,dozero=.true.)
429        call SpMtx_Ax(tmpsol,Restrict,clrhs,dozero=.true.,transp=.true.)
430      else
431        if (sctls%smoothers==-1) then
432          call SpMtx_Ax(tmpsol2,Restrict,csol,dozero=.true.,transp=.true.) ! interpolation
433          tmpsol=0.0_rk
434          call exact_sparse_multismoother(tmpsol,A,tmpsol2)
435        else
436          call SpMtx_Ax(tmpsol,Restrict,csol,dozero=.true.,transp=.true.) ! interpolation
437        endif
438      endif
439
440      if (sctls%method==1) then
441        !call Print_Glob_Vect(sol,M,'sol===',chk_endind=M%ninner)
442        sol(1:A%nrows)=sol(1:A%nrows)+tmpsol(1:A%nrows)
443      elseif (sctls%method==3) then ! fully multiplicative Schwarz
444        sol(1:A%nrows)=sol(1:A%nrows)+tmpsol(1:A%nrows)
445        ! calculate the residual:
446        call SpMtx_Ax(res,A,sol,dozero=.true.) !
447        res=rhs-res
448      elseif (sctls%method==2.and.ol>0) then ! fully multiplicative Schwarz
449        sol(1:A%nrows)=tmpsol(1:A%nrows)
450        ! calculate the residual:
451        call SpMtx_Ax(res,A,sol,dozero=.true.) !
452        res=rhs-res
453      endif
454      if (((ol==0.and.sctls%method==2).or.sctls%method==5).and.sctls%levels>1) then
455        ! multiplicative on fine level, additive with coarse level:
456        sol(1:A%nrows)=sol(1:A%nrows)+tmpsol(1:A%nrows)
457      endif
458    end subroutine prec2Level_solve
459
460  end subroutine prec2Level
461
462  !-------------------------------
463  !> Make preconditioner
464  !-------------------------------
465  subroutine preconditioner(sol,A,rhs,M, &
466               A_interf_,CoarseMtx_,Restrict,refactor_,bugtrack_)
467    use CoarseAllgathers
468    use CoarseMtx_mod
469    use Vect_mod
470    implicit none
471    real(kind=rk),dimension(:),pointer :: sol !< solution
472    type(SpMtx)                        :: A   !< sparse system matrix
473    real(kind=rk),dimension(:),pointer :: rhs !< right hand side
474    type(Mesh),intent(in)              :: M   !< Mesh
475    real(kind=rk),dimension(:),pointer :: res !< residual vector, allocated
476                                              !! here for multiplicative Schwarz
477    type(SpMtx),optional               :: A_interf_  !< matr@interf.
478    type(SpMtx),optional               :: CoarseMtx_ !< Coarse matrix
479    type(SpMtx),optional               :: Restrict   !< Restriction matrix
480    logical,intent(inout),optional :: refactor_
481    logical,optional                   :: bugtrack_
482    ! ----- local: ------
483    integer :: i
484    logical :: add,bugtrack
485    real(kind=rk) :: t1
486    logical :: isFirstIter
487
488    t1 = MPI_WTime()
489
490    if (present(bugtrack_)) then
491      bugtrack=bugtrack_
492    else
493      bugtrack=.false.
494    endif
495    ! ----------------------------
496    isFirstIter = .false.
497    if (present(refactor_)) isFirstIter = refactor_
498
499    if (sctls%method==0) then
500      sol=rhs
501      return
502    endif
503
504    sol=0.0_rk
505    if (sctls%method>1) then ! For multiplicative Schwarz method...:
506      allocate(res(size(rhs)))
507    endif
508     
509    if (sctls%levels>1) then
510      call prec2Level(.true.,A,sol,rhs,res,CoarseMtx_,Restrict,isFirstIter)
511    end if
512
513    ! first level prec
514    call prec1Level(sol,A,rhs,M,res,A_interf_,CoarseMtx_,Restrict,refactor_)
515
516    if (sctls%levels>1) then
517      call prec2Level(.false.,A,sol,rhs,res,CoarseMtx_,Restrict,isFirstIter)
518    end if
519
520    if (sctls%method>1) then ! For multiplicative Schwarz method...:
521      call prec1Level(sol,A,rhs,M,res,A_interf_,CoarseMtx_,Restrict,refactor_)
522      if (associated(res)) deallocate(res)
523    endif
524
525    time_preconditioner = time_preconditioner + MPI_WTime()-t1
526
527  end subroutine preconditioner
528
529  !--------------------------
530  ! Solve
531  !--------------------------
532  subroutine msolve (m, r, z)
533    implicit none
534    real(kind=rk), dimension(:),     intent(in) :: m, r
535    real(kind=rk), dimension(:), intent(in out) :: z
536    integer :: i
537
538    do i = 1, size(r)
539       z(i) = r(i) !/ m(i)
540    end do
541  end subroutine msolve
542
543  !--------------------------
544  !> Preconditioned conjugent gradient method with eigenvalues
545  !--------------------------
546  subroutine pcg_weigs (A,b,x,Msh,it,cond_num,A_interf_,tol_,maxit_, &
547       x0_,solinf,resvects_,CoarseMtx_,Restrict,refactor_)
548    use CoarseAllgathers
549
550    implicit none
551   
552    type(SpMtx),intent(in out)          :: A !< System matrix (sparse)
553    float(kind=rk),dimension(:),pointer :: b !< right hand side
554    float(kind=rk),dimension(:),pointer :: x !< Solution
555    type(Mesh),intent(in)               :: Msh !< Mesh - aux data for Ax operation
556
557    integer,intent(out) :: it
558    real(kind=rk),intent(out) :: cond_num
559   
560    ! Optional arguments
561    type(SpMtx),intent(in out),optional                :: A_interf_ !< matr@interf.
562    real(kind=rk), intent(in), optional                :: tol_ !< Tolerance of the method
563    integer,       intent(in), optional                :: maxit_ !< Max number of iterations
564    float(kind=rk), dimension(:), intent(in), optional :: x0_ !< Initial guess
565    type(ConvInf),            intent(in out), optional :: solinf !< Solution statistics
566    logical,                      intent(in), optional :: resvects_ !< Fill in the 'resvect' or not
567    type(SpMtx),optional                               :: CoarseMtx_ !< Coarse matrix
568    type(SpMtx),optional                               :: Restrict !< Restriction mtx
569    logical,intent(in),optional                        :: refactor_
570   
571    ! Local variables
572    logical :: refactor
573
574    real(kind=rk) :: tol   ! Tolerance
575    integer       :: maxit ! Max number of iterations
576    logical       :: resvects=.false.
577
578    real(kind=rk),dimension(:),pointer,save :: r, p, q, m, z, b_k
579    real(kind=rk),dimension(:),pointer,save :: ztmp !TODO remove me
580    real(kind=rk) :: rho_curr, rho_prev, init_norm, res_norm
581    real(kind=rk) :: tmp,ratio_norm
582    integer :: nfreds
583    integer :: ierr
584    real(kind=rk),dimension(:),pointer,save :: dd,ee,alpha,beta
585    !logical,parameter :: bugtrack=.true.
586    logical,parameter :: bugtrack=.false.
587    ! profiling
588    real(8) :: time_iterations, t1
589
590    write(stream,'(/a)') 'Preconditioned conjugate gradient:'
591    if (present(refactor_).and.refactor_) then
592      refactor=.true.
593    else
594      refactor=.false.
595    endif
596
597    if (size(b) /= size(x)) &
598         call DOUG_abort('[pcg] : SEVERE : size(b) /= size(x)',-1)
599
600    nfreds=size(b)
601    if (.not.associated(r)) then
602      allocate(r(nfreds))
603      allocate(p(nfreds))
604      allocate(q(nfreds))
605      allocate(m(nfreds))
606      allocate(z(nfreds))
607      allocate(b_k(nfreds))
608    endif
609
610    tol = sctls%solve_tolerance
611    if (present(tol_)) &
612         tol = tol_
613
614    maxit = sctls%solve_maxiters
615    if (maxit==-1) maxit=100000
616    if (present(maxit_)) &
617         maxit = maxit_
618
619    if (present(resvects_).and.(.not.present(solinf))) &
620         call DOUG_abort('[pcg] : SEVERE : "resvects_" must be given along'//&
621         ' with "solinf".',-1)
622
623    ! Allocate convergence info structure
624    if (present(solinf).and.(.not.present(resvects_))) then
625       call ConvInf_Init(solinf)
626    else if (present(solinf).and.&
627         (present(resvects_).and.(resvects_.eqv.(.true.)))) then
628       call ConvInf_Init(solinf, maxit)
629       resvects = .true.
630    end if
631
632
633    ! Initialise auxiliary data structures
634    ! to assist with pmvm
635    call pmvmCommStructs_init(A, Msh)
636
637
638if (bugtrack)call Print_Glob_Vect(x,Msh,'global x===')
639    call SpMtx_pmvm(r,A,x,Msh)
640
641    r = b - r
642    init_norm = Vect_dot_product(r,r)
643    if (init_norm == 0.0) &
644         init_norm = 1.0
645
646
647    write(stream,'(a,i6,a,e8.2)') 'maxit = ',maxit,', tol = ',tol
648    write(stream,'(a,e22.15)') 'init_norm = ', dsqrt(init_norm)
649
650    it = 0
651    ratio_norm = 1.0_rk
652    ! arrays for eigenvalue calculation:
653    if (.not.associated(dd)) then
654      allocate(dd(maxit))
655      allocate(ee(maxit))
656      allocate(alpha(maxit))
657      allocate(beta(maxit))
658    endif
659
660    time_iterations = 0.
661    ! iterations
662    do while((ratio_norm > tol*tol).and.(it < maxit))
663      it = it + 1
664      t1 = MPI_WTime()
665
666if (bugtrack)call Print_Glob_Vect(r,Msh,'global r===',chk_endind=Msh%ninner)
667      call preconditioner(sol=z,          &
668                            A=A,          &
669                          rhs=r,          &
670                            M=Msh,        &
671                    A_interf_=A_interf_,  &
672                   CoarseMtx_=CoarseMtx_, &
673                    Restrict=Restrict,    &
674                    refactor_=refactor,   &
675                    bugtrack_=bugtrack)
676
677      refactor=.false.
678if (bugtrack)call Print_Glob_Vect(z,Msh,'global bef comm z===',chk_endind=Msh%ninner)
679      if (sctls%method/=0) then
680        call Add_common_interf(z,A,Msh)
681      endif
682!call Print_Glob_Vect(z,Msh,'global aft comm z===',chk_endind=Msh%ninner)
683!call Print_Glob_Vect(z,Msh,'global z===')
684      ! compute current rho
685      rho_curr = Vect_dot_product(r,z)
686
687      if (it == 1) then
688         p = z
689      else
690         beta(it) = rho_curr / rho_prev
691         p = z + beta(it) * p
692      end if
693      call SpMtx_pmvm(q,A, p, Msh)
694if (bugtrack)call Print_Glob_Vect(q,Msh,'global q===')
695      ! compute alpha
696      alpha(it) = rho_curr / Vect_dot_product(p,q)
697      x = x + alpha(it) * p
698if (bugtrack)call Print_Glob_Vect(x,Msh,'global x===')
699      r = r - alpha(it) * q
700if (bugtrack)call Print_Glob_Vect(r,Msh,'global r===')
701      rho_prev = rho_curr
702      ! check
703      res_norm = Vect_dot_product(r,r)
704      !write (stream,*) "Norm is", res_norm
705      ratio_norm = res_norm / init_norm
706
707      time_iterations = time_iterations + MPI_WTime()-t1
708
709      if (ismaster()) &
710           write(stream, '(i5,a,e22.15)') it,': res_norm=',dsqrt(res_norm)
711    end do
712
713    if(pstream/=0) then
714       write(pstream, "(I0,':pcg iterations:',I0)") myrank, it
715       write(pstream, "(I0,':iterations time:',F0.3)") myrank, time_iterations
716       write(pstream, "(I0,':preconditioner time:',F0.3)") myrank, time_preconditioner
717    end if
718
719    if (ismaster()) then
720      call CalculateEigenvalues(it,dd,ee,alpha,beta,maxit)
721      cond_num=dd(it)/dd(1)
722      write(stream,'(a,i3,a,e10.4)') '#it:',it,' Cond#: ',cond_num
723    endif
724    !deallocate(beta)
725    !deallocate(alpha)
726    !deallocate(ee)
727    !deallocate(dd)
728    ! Deallocate auxiliary data structures
729    ! helped to assist with pmvm
730 !  call pmvmCommStructs_destroy()
731
732    !deallocate(b_k)
733    !deallocate(z)
734    !deallocate(m)
735    !deallocate(q)
736    !deallocate(p)
737    !deallocate(r)
738  end subroutine pcg_weigs
739
740
741  subroutine CalculateEigenvalues(it,dd,ee,alpha,beta,MaxIt)
742    ! Finds eigenvalues using Lanczos connection
743    implicit none
744    integer :: it,MaxIt
745    real(kind=rk),dimension(:),pointer :: dd,ee,alpha,beta
746    integer :: i,j,ierr
747
748    dd(1) = 1.0_rk/alpha(1)
749    ee(1) = 0.0_rk
750    do i=2,it
751      if (alpha(i)==0.or.beta(i)<0) then
752        print *,'Unable to compute eigenvalue number',i,' and '
753        do j=1,i
754          print *,j,' alpha:',alpha(j),' beta:',beta
755        enddo
756        return
757      else
758        dd(i) = 1.0_rk/alpha(i) + beta(i)/alpha(i-1)
759        ee(i) = -dsqrt(beta(i))/alpha(i-1)
760      endif
761    enddo
762    !call tql1(it,dd,ee,MaxIt,ierr)
763    call tql1(it,dd,ee,ierr)
764    if (ierr > 0) then
765      print *,'Cancelled after EigMaxIt while calculating eig',ierr
766    endif
767  end subroutine CalculateEigenvalues
768
769  subroutine tql1(n,d,e,ierr)
770    implicit none
771    integer :: i,j,l,m,n,ii,l1,l2,mml,ierr
772    real(kind=rk) :: d(n),e(n)
773    real(kind=rk) :: c,c2,c3,dl1,el1,f,g,h,p,r,s,s2,tst1,tst2 !,pythag
774!
775!       this subroutine is a translation of the algol procedure tql1,
776!       num. math. 11, 293-306(1968) by bowdler, martin, reinsch, and
777!       wilkinson.
778!       handbook for auto. comp., vol.ii-linear algebra, 227-240(1971).
779!
780!       this subroutine finds the eigenvalues of a symmetric
781!       tridiagonal matrix by the ql method.
782!
783!       on input
784!          n is the order of the matrix.
785!          d contains the diagonal elements of the input matrix.
786!          e contains the subdiagonal elements of the input matrix
787!            in its last n-1 positions.  e(1) is arbitrary.
788!
789!        on output
790!          d contains the eigenvalues in ascending order.  if an
791!            error exit is made, the eigenvalues are correct and
792!            ordered for indices 1,2,...ierr-1, but may not be
793!            the smallest eigenvalues.
794!          e has been destroyed.
795!          ierr is set to
796!            zero       for normal return,
797!            j          if the j-th eigenvalue has not been
798!                       determined after 30 iterations.
799!       calls pythag for  sqrt(a*a + b*b) .
800!
801!       questions and comments should be directed to burton s. garbow,
802!       mathematics and computer science div, argonne national laboratory
803!
804!       this version dated august 1983.
805!
806!       ------------------------------------------------------------------
807!
808        ierr = 0
809        if (n .eq. 1) go to 1001
810!
811        do 100 i = 2, n
812    100 e(i-1) = e(i)
813!
814        f = 0.0e0
815        tst1 = 0.0e0
816        e(n) = 0.0e0
817
818        do 290 l = 1, n
819           j = 0
820           h = abs(d(l)) + abs(e(l))
821           if (tst1 .lt. h) tst1 = h
822!       .......... look for small sub-diagonal element ..........
823           do 110 m = l, n
824              tst2 = tst1 + abs(e(m))
825              if (tst2 .eq. tst1) go to 120
826!       .......... e(n) is always zero, so there is no exit
827!                  throu     gh the bottom of the loop ..........
828    110    continue
829
830    120    if (m .eq. l)      go to 210
831    130    if (j .eq. 30     ) go to 1000
832           j = j + 1
833!       .......... form shift ..........
834           l1 = l + 1
835           l2 = l1 + 1
836           g = d(l)
837           p = (d(l1) - g) / (2.0e0 * e(l))
838           r = pythag(p,1.0e0_rk)
839           d(l) = e(l) / (p + sign(r,p))
840           d(l1) = e(l) * (p + sign(r,p))
841           dl1 = d(l1)
842           h = g - d(l)
843           if (l2 .gt. n) go to 145
844
845           do 140 i = l2, n
846    140    d(i) = d(i) - h
847
848    145    f = f + h
849!       .......... ql transformation ..........
850           p = d(m)
851           c = 1.0e0
852           c2 = c
853           el1 = e(l1)
854           s = 0.0e0
855           mml = m - l
856!       .......... for i=m-1 step -1 until l do -- ..........
857           do 200 ii = 1, mml
858              c3 = c2
859              c2 = c
860              s2 = s
861              i = m - ii
862              g = c * e(i)
863              h = c * p
864              r = pythag(p,e(i))
865              e(i+1) = s * r
866              s = e(i) / r
867              c = p / r
868              p = c * d(i) - s * g
869              d(i+1) = h + s * (c * g + s * d(i))
870    200    continue
871
872           p = -s * s2 * c3 * el1 * e(l) / dl1
873           e(l) = s * p
874           d(l) = c * p
875           tst2 = tst1 + abs(e(l))
876           if (tst2 .gt. tst1) go to 130
877    210    p = d(l) + f
878!       .......... order eigenvalues ..........
879           if (l .eq. 1) go to 250
880!       .......... for i=l step -1 until 2 do -- ..........
881           do 230 ii = 2, l
882              i = l + 2 - ii
883              if (p .ge. d(i-1)) go to 270
884              d(i) = d(i-1)
885    230    continue
886
887    250    i = 1
888    270    d(i) = p
889    290 continue
890
891        go to 1001
892!       .......... set error -- no convergence to an
893!                  eigenvalue after 30 iterations ..........
894   1000 ierr = l
895   1001 return
896  end subroutine tql1
897
898  function pythag(a,b) result(pyt)
899    ! finds dsqrt(a**2+b**2) without overflow or destructive underflow
900    implicit none
901    real(kind=rk) :: a,b,pyt
902    real(kind=rk) :: p,r,s,t,u
903
904    p = dmax1(dabs(a),dabs(b))
905    if (p .eq. 0.0d0) go to 20
906    r = (dmin1(dabs(a),dabs(b))/p)**2
907 10 continue
908    t = 4.0d0 + r
909    if (t .eq. 4.0d0) go to 20
910    s = r/t
911    u = 1.0d0 + 2.0d0*s
912    p = u*p
913    r = (s/u)**2 * r
914    go to 10
915 20 pyt = p
916    return
917  end function pythag
918
919
920end module pcg_mod
921
922
Note: See TracBrowser for help on using the repository browser.