~nickpapior/siesta/tddft-work

« back to all changes in this revision

Viewing changes to Src/rdiag_mrrr.F

  • Committer: Rafi Ullah
  • Date: 2017-08-30 14:09:10 UTC
  • mfrom: (611.1.19 trunk)
  • Revision ID: rraffiu@gmail.com-20170830140910-bhu0osuh4d59wn8e
Merged with trunk-630

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
! ---
2
 
! Copyright (C) 1996-2016       The SIESTA group
3
 
!  This file is distributed under the terms of the
4
 
!  GNU General Public License: see COPYING in the top directory
5
 
!  or http://www.gnu.org/copyleft/gpl.txt .
6
 
! See Docs/Contributors.txt for a list of contributors.
7
 
! ---
8
 
      module m_rdiag_mrrr
9
 
      implicit none
10
 
 
11
 
#ifndef SIESTA__NO_MRRR
12
 
      public :: rdiag_mrrr
13
 
 
14
 
      CONTAINS
15
 
      subroutine rdiag_mrrr(H,S,n,nm,nml,w,Z,neigvec,ierror)
16
 
! ***************************************************************************
17
 
! Subroutine to find a subset of eigenvalues and eigenvectors of the
18
 
! real general eigenvalue problem  H z = w S z,  with H and S
19
 
! real symmetric matrices. It uses the MRRR algorithm.
20
 
 
21
 
! Written by A. Garcia (Jan 2014), based on rdiag.
22
 
 
23
 
! ************************** INPUT ******************************************
24
 
! real*8 H(nml,nm)                 : Symmetric H matrix
25
 
! real*8 S(nml,nm)                 : Symmetric S matrix
26
 
! integer n                        : Order of the generalized  system
27
 
! integer nm                       : Right hand dimension of H and S matrices
28
 
! integer nml                      : Left hand dimension of H and S matrices
29
 
!                                    which is greater than or equal to nm
30
 
! integer neigvec                  : No. of eigenvectors to calculate
31
 
! ************************** OUTPUT *****************************************
32
 
! real*8 w(nml)                    : Eigenvalues
33
 
! real*8 Z(nml,nm)                 : Eigenvectors
34
 
! integer ierror                   : Flag indicating success code for routine
35
 
!                                  :  0 = success
36
 
!                                  :  1 = fatal error
37
 
 
38
 
!  Modules
39
 
      use precision
40
 
      use parallel,   only : Node, Nodes, BlockSize
41
 
#ifdef MPI
42
 
      use mpi_siesta, only : mpi_comm_world
43
 
#endif
44
 
      use alloc
45
 
      use sys,        only : die
46
 
 
47
 
      implicit          none
48
 
 
49
 
! Passed variables
50
 
      integer, intent(out)                 :: ierror
51
 
      integer, intent(in)                  :: n
52
 
      integer, intent(in)                  :: neigvec
53
 
      integer, intent(in)                  :: nm
54
 
      integer, intent(in)                  :: nml
55
 
      real(dp), intent(in)                 :: H(nml,nm)
56
 
      real(dp), intent(in)                 :: S(nml,nm)
57
 
 
58
 
      ! It should be possible to dimension Z to use the
59
 
      ! actual number of eigenvectors needed...
60
 
      real(dp), intent(out)                :: w(nml)
61
 
      real(dp), intent(out)                :: Z(nml,nm)
62
 
 
63
 
#ifdef MPI
64
 
      integer                 :: desch(9)
65
 
      integer                 :: MPIerror, mpi_comm_rows, mpi_comm_cols
66
 
      integer                 :: ictxt
67
 
      integer                 :: np0
68
 
      integer                 :: np_cols_1d
69
 
      integer                 :: np_rows_1d
70
 
      real(dp)                :: dscale
71
 
      logical                 :: BlacsOK
72
 
 
73
 
! Additional variables for a 2D proc grid
74
 
      integer                 :: np_rows, np_cols
75
 
      integer                 :: my_prow, my_pcol
76
 
      integer                 :: i2d_ctxt
77
 
      integer, dimension(9)   :: desc_h2d
78
 
 
79
 
      integer :: neigok, nz, vl, vu
80
 
      character(len=256) :: msg
81
 
      
82
 
! Matrices for 2D
83
 
      real(dp), pointer, dimension(:,:) ::  h2d =>null()
84
 
      real(dp), pointer, dimension(:,:) ::  s2d =>null()
85
 
      real(dp), pointer, dimension(:,:) ::  z2d =>null()
86
 
      integer ::  nh_rows, nh_cols
87
 
 
88
 
      integer                 :: info, i, n_col, n_row
89
 
      integer                 :: lwork, liwork
90
 
      real(dp), pointer       :: work(:) => null()
91
 
      integer , pointer       :: iwork(:) => null()
92
 
 
93
 
      real(dp), parameter     :: zero = 0.0_dp
94
 
      real(dp), parameter     :: one = 1.0_dp
95
 
 
96
 
      integer, external       :: numroc, indxl2g
97
 
 
98
 
!***********************************************************************
99
 
! Setup                                                                *
100
 
!***********************************************************************
101
 
      
102
 
!     Initialise error flag
103
 
      ierror = 0
104
 
      
105
 
      if ( n == 1 ) then
106
 
         w(:) = zero
107
 
         w(1) = H(1,1) / S(1,1)
108
 
         Z(:,:) = zero
109
 
         Z(1,1) = one / sqrt(S(1,1))
110
 
         return
111
 
      end if
112
 
      
113
 
!     Start time count
114
 
      call timer('rdiag_mrrr',1)
115
 
      
116
 
      
117
 
! Get Blacs context and initialise Blacs grid for main grid
118
 
      
119
 
      ! First, declare explicitly a context for the original
120
 
      ! distribution, which is block-cyclic over the columns,
121
 
      ! since our matrices are dimensioned as H(n,no_l) in diagg,
122
 
      ! i.e., each processor contains all the rows but just no_l
123
 
      ! columns.
124
 
      np_rows_1d = 1
125
 
      np_cols_1d = Nodes
126
 
      call blacs_get( -1, 0, ictxt )
127
 
      ! The design of the BLACS is weird.
128
 
      ! The above call is equivalent to setting:
129
 
      ictxt = mpi_comm_world    ! or whatever comm we are using
130
 
      ! The following call will OVERWRITE ictxt with a new context
131
 
      ! "C" means "column-major" ordering, which is not surprising,
132
 
      ! since we have np_rows_1d = 1
133
 
      call blacs_gridinit( ictxt, 'C', np_rows_1d, np_cols_1d )
134
 
      
135
 
      
136
 
      ! Set up blacs descriptors for parallel case
137
 
      BlacsOK = .true.
138
 
      ! This is wrong in the BSs
139
 
      ! since the effective row blocksize is n. It should be
140
 
      !                     n, n, n        , BlockSize
141
 
      call descinit( desch, n, n, BlockSize, BlockSize, 0, 0, 
142
 
     .     ictxt, n, info )
143
 
      if (info.ne.0) BlacsOK = .false.
144
 
      if (.not.BlacsOK) then
145
 
         call die('ERROR : Blacs setup has failed in rdiag!')
146
 
      endif
147
 
      
148
 
      ! Setup secondary grid for 2D distribution
149
 
      
150
 
      ! Selection of number of processor rows/columns
151
 
      ! We try to set up the grid square-like, i.e. start the search for possible
152
 
      ! divisors of Nodes with a number next to the square root of Nodes
153
 
      ! and decrement it until a divisor is found.
154
 
      
155
 
      do np_rows = NINT(SQRT(REAL(Nodes))),2,-1
156
 
         if(mod(Nodes,np_rows) == 0 ) exit
157
 
      end do
158
 
      ! at the end of the above loop, Nodes is always divisible by np_rows
159
 
      
160
 
      np_cols = Nodes/np_rows
161
 
      
162
 
      !if (Node == 0) print *, "np_rows, col: ", np_rows, np_cols
163
 
      
164
 
      !call blacs_get(ictxt, 10, i2d_ctxt)
165
 
      i2d_ctxt = mpi_comm_world ! or whatever comm we are using
166
 
      ! after the above call, i2d_ctxt will contain the communicator
167
 
      ! handle we used to initialize ictxt
168
 
      ! Now we set up the process grid in row-major, or "natural" order.
169
 
      !    0   1   2   3
170
 
      !    4   5   6   7
171
 
      call blacs_gridinit(i2d_ctxt, 'R', np_rows, np_cols)
172
 
      
173
 
      ! We need this call to know who we are (my_prow, my_pcol)
174
 
      call blacs_gridinfo(i2d_ctxt, np_rows, np_cols,
175
 
     .     my_prow, my_pcol)
176
 
      !if (Node == 0) print *, "ictxt, i2_ctxt:", ictxt, i2d_ctxt
177
 
      
178
 
      ! Enquire size of local part of 2D matrices
179
 
      ! since we are going to change and in principle we do not know.
180
 
      
181
 
      ! We might want to change the value of BlockSize...
182
 
      
183
 
      nh_rows = numroc(n, BlockSize, my_prow, 0, np_rows)
184
 
      nh_cols = numroc(n, BlockSize, my_pcol, 0, np_cols)
185
 
      
186
 
      ! Set up blacs descriptors for 2D case
187
 
      ! It is only necessary to give the leading (row) dimension of the array.
188
 
      call descinit(desc_h2d, n, n, Blocksize, BlockSize, 0, 0,
189
 
     .     i2d_ctxt,  nh_rows, info)
190
 
      if (info.ne.0) BlacsOK = .false.
191
 
      if (.not.BlacsOK) then
192
 
         call die('ERROR : Blacs setup has failed in rdiag!')
193
 
      endif
194
 
      
195
 
      ! Set up workspace arrays for 2D versions of 1D arrays
196
 
      call re_alloc( h2d, 1, nh_rows, 1, nh_cols, name='h2d')
197
 
      call re_alloc( s2d, 1, nh_rows, 1, nh_cols, name='s2d')
198
 
      call re_alloc( z2d, 1, nh_rows, 1, nh_cols, name='z2d')
199
 
      
200
 
      ! Copy arrays to new 2D distribution
201
 
      call pdgemr2d(n, n, H, 1, 1, desch, h2d, 1, 1, desc_h2d, ictxt)
202
 
      call pdgemr2d(n, n, S, 1, 1, desch, s2d, 1, 1, desc_h2d, ictxt)
203
 
      
204
 
      np0 = numroc(n,BlockSize,0,0,np_rows)
205
 
      ! lwork is used also in the forward transform.
206
 
      ! It will be reset below
207
 
      lwork = max(BlockSize*(np0+1),3*BlockSize)
208
 
      liwork = 3                ! for now: see query below
209
 
 
210
 
!     Allocate workspace arrays
211
 
      call re_alloc( work,    1,lwork,   name='work'  )
212
 
      call re_alloc( iwork,   1,liwork,  name='iwork'  )
213
 
      
214
 
!*************************************************************************
215
 
! Transform problem to standard eigenvalue problem                             
216
 
! by first factorizing the overlap matrix by Cholesky
217
 
!*************************************************************************
218
 
      call timer('rdiag1',1)
219
 
      
220
 
      call pdpotrf('U',n,s2d,1,1,desc_h2d,info)
221
 
      if (info.ne.0) then
222
 
         call die('Error in Cholesky factorisation in rdiag')
223
 
      endif
224
 
      call timer('rdiag1',2)
225
 
      
226
 
      !
227
 
      ! Now transform
228
 
      !
229
 
      call timer('rdiag2',1)
230
 
      
231
 
      call pdsyngst(1,'U',n,h2d,1,1,desc_h2d,s2d,1,1,
232
 
     .     desc_h2d,dscale,work,lwork,info)
233
 
      if (info.ne.0) then
234
 
         call die('Error in forward transformation in rdiag')
235
 
      endif
236
 
      call timer('rdiag2',2)
237
 
      
238
 
!     Solve standard eigenvalue problem 
239
 
      call timer('rdiag3',1)
240
 
 
241
 
      ! Find the optimal work-space sizes
242
 
      lwork = -1
243
 
      liwork = -1
244
 
      call pdsyevr('V','I','U',n,h2d,1,1,desc_h2d,vl,vu,1,
245
 
     .     neigvec,neigok,nz,w,z2d,1,1,
246
 
     .     desc_h2d,work,lwork,iwork,liwork,info)
247
 
      if (info /= 0) then
248
 
         write(msg,"(a,i0)") "Error in pdsyevr work estim. Info: ",
249
 
     $        info
250
 
         call die(msg)
251
 
      endif
252
 
      lwork = nint(work(1))
253
 
      liwork = iwork(1)
254
 
      call re_alloc(work, 1, lwork)
255
 
      call re_alloc(iwork, 1, liwork)
256
 
 
257
 
      call pdsyevr('V','I','U',n,h2d,1,1,desc_h2d,vl,vu,1,
258
 
     .     neigvec,neigok,nz,w,z2d,1,1,
259
 
     .     desc_h2d,work,lwork,iwork,liwork,info)
260
 
      
261
 
      if (info /= 0) then
262
 
         write(msg,"(a,i0)") "Error in pdsyevr. Info: ", info
263
 
         call die(msg)
264
 
      endif
265
 
      if (node==0) then
266
 
         if ((neigok /= neigvec)) then
267
 
            write(6,"(a,2i7)") "*** Warning: eigenpair mismatch:"
268
 
            write(6,"(a,3i7)")
269
 
     $           "Eigenvalues requested and found (w,z): ",
270
 
     $           neigvec , neigok, nz
271
 
            write(0,"(a,2i7)") "*** Warning: eigenpair mismatch:"
272
 
            write(0,"(a,3i7)")
273
 
     $           "Eigenvalues requested and found (w,z): ",
274
 
     $           neigvec , neigok, nz
275
 
         endif
276
 
      endif
277
 
 
278
 
      call timer('rdiag3',2)
279
 
      
280
 
!********************************************************************
281
 
! Back transformation                                               *
282
 
!********************************************************************
283
 
      call timer('rdiag4',1)
284
 
      
285
 
      call pdtrsm('Left','U','N','Non-unit',n,neigvec,one,
286
 
     .     s2d,1,1,desc_h2d,z2d,1,1,desc_h2d)
287
 
      ! Return to 1-D block-cyclic distribution
288
 
      call pdgemr2d(n,n,z2d,1,1,desc_h2d,Z,1,1,desch,ictxt)
289
 
      if (dscale.ne.one) then
290
 
         call dscal(n,dscale,w,1)
291
 
      endif
292
 
      
293
 
      if (info.ne.0) then
294
 
         call die('Error in back transformation in rdiag')
295
 
      endif
296
 
      call timer('rdiag4',2)
297
 
      
298
 
      CALL BLACS_GRIDEXIT( ICTXT )
299
 
      CALL BLACS_GRIDEXIT( I2D_CTXT )
300
 
 
301
 
!     Deallocate workspace arrays
302
 
      call de_alloc( work,    name='work'   )
303
 
      call de_alloc( iwork,   name='iwork'  )
304
 
      
305
 
      
306
 
      call de_alloc( h2d,   name='h2d'  )
307
 
      call de_alloc( s2d,   name='s2d'  )
308
 
      call de_alloc( z2d,   name='z2d'  )
309
 
      
310
 
      call timer('rdiag_mrrr',2)
311
 
      
312
 
#endif MPI
313
 
      end subroutine rdiag_mrrr
314
 
#else
315
 
      ! Some compilers do not allow empty modules
316
 
      CONTAINS
317
 
      subroutine rdiag_mrrr_dummy()
318
 
      end subroutine
319
 
#endif      
320
 
      end module m_rdiag_mrrr