~nickpapior/siesta/tddft-work

« back to all changes in this revision

Viewing changes to Src/rdiag.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
 
      subroutine rdiag(H,S,n,nm,nml,w,Z,neigvec,iscf,ierror)
9
 
C ***************************************************************************
10
 
C Subroutine  to solve all eigenvalues and eigenvectors of the
11
 
C real general eigenvalue problem  H z = w S z,  with H and S
12
 
C real symmetric matrices.
13
 
C Written by G.Fabricius and J.Soler, March 1998
14
 
C Rewritten by Julian Gale, August 2004
15
 
C ************************** INPUT ******************************************
16
 
C real*8 H(nml,nm)                 : Symmetric H matrix
17
 
C real*8 S(nml,nm)                 : Symmetric S matrix
18
 
C integer n                        : Order of the generalized  system
19
 
C integer nm                       : Right hand dimension of H and S matrices
20
 
C integer nml                      : Left hand dimension of H and S matrices
21
 
C                                    which is greater than or equal to nm
22
 
C integer neigvec                  : No. of eigenvectors to calculate
23
 
C integer iscf                     : SCF cycle
24
 
C ************************** OUTPUT *****************************************
25
 
C real*8 w(nml)                    : Eigenvalues
26
 
C real*8 Z(nml,nm)                 : Eigenvectors
27
 
C integer ierror                   : Flag indicating success code for routine
28
 
C                                  :  0 = success
29
 
C                                  : -1 = repeat call as memory is increased
30
 
C                                  :  1 = fatal error
31
 
C ************************* PARALLEL ****************************************
32
 
C When running in parallel this routine now uses Scalapack to perform a
33
 
C parallel matrix diagonalisation. This requires Scalapack and Blacs to
34
 
C be installed first. Although globally a 1-D block cyclic data distribution
35
 
C is employed, locally 1 or 2-D distributions are allowed for. 
36
 
C The routine allows access to all the phases of diagonalisation for fuller
37
 
C control, and allows for parallel divide and conquer with reduced memory.
38
 
C The presence of eigenvalue clusters is checked for and the memory adjusted
39
 
C accordingly to try to guarantee convergence.
40
 
C Note that the blacs grid is only initialised on the first call to avoid
41
 
C exceeding MPI limits for split/group creation.
42
 
C ***************************************************************************
43
 
C
44
 
C  Modules
45
 
C
46
 
      use precision
47
 
      use fdf
48
 
      use parallel,   only : Node, Nodes, BlockSize, ProcessorY
49
 
      use diagmemory, only : MemoryFactor
50
 
      use alloc,      only : re_alloc, de_alloc, allocdefaults,
51
 
     &                       alloc_default
52
 
      use sys,        only : die
53
 
      use m_diagon_opt,only : saveeigenvectors, maxclustersize, serial,
54
 
     &                       i2d_ctxt, noexpert, divideconquer, use2d,
55
 
     &                       prerotate, ictxt, allinone, doread,
56
 
     &                       firstcall
57
 
#ifdef MPI
58
 
      use mpi_siesta
59
 
#endif
60
 
      implicit          none
61
 
 
62
 
C Passed variables
63
 
      integer                 :: ierror
64
 
      integer                 :: iscf
65
 
      integer                 :: n
66
 
      integer                 :: neigvec
67
 
      integer                 :: nm
68
 
      integer                 :: nml
69
 
      real(dp)                :: H(nml,nm)
70
 
      real(dp)                :: S(nml,nm)
71
 
      real(dp)                :: w(nml)
72
 
      real(dp)                :: Z(nml,nm)
73
 
 
74
 
C Local variables
75
 
      type(allocDefaults) oldDefaults
76
 
#ifdef MPI
77
 
      integer                 :: MPIerror
78
 
      integer                 :: anb
79
 
      integer                 :: clustersize
80
 
      integer                 :: desch(9)
81
 
      integer                 :: iacol
82
 
      integer                 :: iarow
83
 
      integer                 :: iceil
84
 
      integer                 :: indxg2p
85
 
      integer                 :: lwork2
86
 
      integer                 :: mq0
87
 
      integer                 :: mycol
88
 
      integer                 :: myrow
89
 
      integer                 :: nc
90
 
      integer                 :: nz
91
 
      integer                 :: nn
92
 
      integer                 :: np
93
 
      integer                 :: np0
94
 
      integer                 :: npcol
95
 
      integer                 :: nprow
96
 
      integer                 :: nps
97
 
      integer                 :: nq
98
 
      integer                 :: nsygst_lwopt
99
 
      integer                 :: nsytrd_lwopt
100
 
      integer                 :: nt
101
 
      integer                 :: numroc
102
 
      integer                 :: oldmaxclustersize
103
 
      integer                 :: pjlaenv
104
 
      integer                 :: sqnpc
105
 
      real(dp)                :: dscale
106
 
      logical                 :: BlacsOK
107
 
      logical                 :: lBtmp(5)
108
 
C Additional variables for a 2D proc grid
109
 
      integer                 :: np2d_row, np2d_col
110
 
      integer                 :: my2d_row, my2d_col
111
 
      integer, dimension(9)   :: desc_h2d
112
 
      
113
 
C Matrices for 2D
114
 
      integer ::  mat_2d_row, mat_2d_col
115
 
#endif
116
 
      character            :: jobz
117
 
      character            :: range
118
 
      integer              :: ilaenv
119
 
      integer              :: info
120
 
      integer              :: liwork
121
 
      integer              :: lwork
122
 
      integer              :: nb
123
 
      integer              :: neigok
124
 
      logical              :: ChangeAlgorithm
125
 
      real(dp)             :: vl
126
 
      real(dp)             :: vu
127
 
#ifdef MPI
128
 
#ifdef SCALAPACK_DEBUG
129
 
      integer              :: d_lwork, d_lrwork, d_liwork
130
 
      logical,        save :: debugged = .false.
131
 
#endif
132
 
#endif
133
 
 
134
 
      real(dp),  parameter :: abstol = 1.0e-8_dp
135
 
      real(dp),  parameter :: orfac = 1.0e-3_dp
136
 
      real(dp),  parameter :: zero = 0.0_dp
137
 
      real(dp),  parameter :: one = 1.0_dp
138
 
 
139
 
      integer,     pointer :: iclustr(:), ifail(:), iwork(:)
140
 
      real(dp),    pointer :: gap(:), work(:), Zsave(:,:),
141
 
     &                        h2d(:,:), s2d(:,:), z2d(:,:)
142
 
 
143
 
C     Start time count
144
 
      call timer('rdiag',1)
145
 
 
146
 
C     Nullify pointers
147
 
      nullify( iclustr, ifail, iwork, gap, work, Zsave, h2d, s2d, z2d )
148
 
 
149
 
C     Get old allocation defaults and set new ones
150
 
      call alloc_default( old=oldDefaults, copy=.false., shrink=.true.,
151
 
     &                    imin=1, routine='rdiag' )
152
 
 
153
 
C*******************************************************************************
154
 
C Setup                                                                        *
155
 
C*******************************************************************************
156
 
 
157
 
C Initialise error flag
158
 
      ierror = 0
159
 
 
160
 
! Trap n=1 case, which is not handled correctly otherwise (JMS 2011/07/19)
161
 
      if (n==1) then
162
 
        w(:) = zero
163
 
        w(1) = H(1,1) / S(1,1)
164
 
        Z(:,:) = zero
165
 
        Z(1,1) = one / sqrt(S(1,1))
166
 
        goto 1000   ! exit point
167
 
      end if
168
 
 
169
 
! vl and vu are not currently used, but they must be initialized
170
 
      vl = 0
171
 
      vu = n
172
 
 
173
 
C Set algorithm logicals
174
 
      if (DoRead) then
175
 
        DoRead = .false.
176
 
        AllInOne      = fdf_boolean('Diag.AllInOne',.false.)
177
 
        DivideConquer = fdf_boolean('Diag.DivideAndConquer',.true.)
178
 
        NoExpert      = fdf_boolean('Diag.NoExpert',.false.)
179
 
        PreRotate     = fdf_boolean('Diag.PreRotate',.false.)
180
 
        Use2D         = fdf_boolean('Diag.Use2D',.true.)
181
 
 
182
 
#ifdef MPI
183
 
        if (Node.eq.0) then
184
 
           lBtmp(1) = AllInOne
185
 
           lBtmp(2) = DivideConquer
186
 
           lBtmp(3) = NoExpert
187
 
           lBtmp(4) = PreRotate
188
 
           lBtmp(5) = Use2D
189
 
        endif
190
 
        call MPI_Bcast(lBtmp,5,MPI_logical,0,MPI_Comm_World,MPIerror)
191
 
        AllInOne = lBtmp(1)
192
 
        DivideConquer = lBtmp(2)
193
 
        NoExpert = lBtmp(3)
194
 
        PreRotate = lBtmp(4)
195
 
        Use2D = lBtmp(5)
196
 
#endif
197
 
        Serial = (Nodes.eq.1)
198
 
        if (Serial) Use2D = .false.
199
 
        if (AllInOne.and.Serial) DivideConquer = .false.
200
 
        if (neigvec.ne.n) PreRotate = .false.
201
 
        if (PreRotate) SaveEigenvectors = .true.
202
 
        if (Nodes.eq.1) Use2D = .false.
203
 
        if (SaveEigenvectors) then
204
 
          if (Use2D) then
205
 
            call die('Zsave not dimensioned in rdiag')
206
 
          else
207
 
            call re_alloc( Zsave, 1, nml, 1, nm, 'Zsave', 'rdiag' )
208
 
          endif
209
 
        endif
210
 
      endif
211
 
 
212
 
C Is it time to switch from standard diagonaliser?
213
 
      ChangeAlgorithm = (iscf.gt.2)
214
 
 
215
 
#ifdef MPI
216
 
      if (.not.Serial) then
217
 
C Get Blacs context and initialise Blacs grid for main grid
218
 
        nprow = 1
219
 
        npcol = Nodes
220
 
        if (FirstCall) then
221
 
!         JMS: Changed to allow mpi_comm_world to be supplanted in MPI_siesta.
222
 
!         The change has no effect otherwise, since blacs_get returns the
223
 
!         true value of mpi_comm_world (usually zero) as ictxt
224
 
!          call blacs_get( -1, 0, ictxt )   ! removed
225
 
          ictxt = mpi_comm_world            ! added
226
 
          call blacs_gridinit( ictxt, 'C', nprow, npcol )
227
 
        endif
228
 
 
229
 
        if (Use2D) then
230
 
C If 2D approach is being used then setup secondary grid
231
 
          np2d_row = processorY
232
 
          np2d_col = Nodes/processorY
233
 
          if (FirstCall) then
234
 
            call blacs_get(ictxt, 10, i2d_ctxt)
235
 
            call blacs_gridinit(i2d_ctxt, 'R', np2d_row, np2d_col)
236
 
          endif
237
 
          call blacs_gridinfo(i2d_ctxt, np2d_row, np2d_col,
238
 
     &       my2d_row, my2d_col)
239
 
        endif
240
 
 
241
 
C Set up blacs descriptors for parallel case
242
 
        BlacsOK = .true.
243
 
        call descinit( desch, n, n, BlockSize, BlockSize, 0, 0, 
244
 
     &                 ictxt, n, info )
245
 
        if (info.ne.0) BlacsOK = .false.
246
 
        if (.not.BlacsOK) then
247
 
          call die('ERROR : Blacs setup has failed in rdiag!')
248
 
        endif
249
 
 
250
 
        if (Use2D) then
251
 
C Enquire size of local part of 2D matices
252
 
          mat_2d_row = numroc(n, BlockSize, my2d_row, 0, np2d_row)
253
 
          mat_2d_col = numroc(n, BlockSize, my2d_col, 0, np2d_col)
254
 
 
255
 
C Set up blacs descriptors for 2D case
256
 
          call descinit(desc_h2d, n, n, Blocksize, BlockSize, 0, 0,
257
 
     &                  i2d_ctxt,  mat_2d_row, info)
258
 
          if (info.ne.0) BlacsOK = .false.
259
 
          if (.not.BlacsOK) then
260
 
            call die('ERROR : Blacs setup has failed in rdiag!')
261
 
          endif
262
 
        endif
263
 
 
264
 
      endif
265
 
#endif
266
 
 
267
 
C Set general Lapack parameters
268
 
      if (neigvec.gt.0) then
269
 
        jobz   = 'V'
270
 
        if (neigvec.eq.n) then
271
 
          range  = 'A'
272
 
        else
273
 
          range  = 'I'
274
 
        endif
275
 
      else
276
 
        jobz   = 'N'
277
 
        range  = 'A'
278
 
      endif
279
 
 
280
 
C Calculate memory requirements
281
 
      if (Serial) then
282
 
        if (DivideConquer) then
283
 
          if (neigvec.gt.0) then
284
 
            lwork = 1 + 6*n + n*n
285
 
            liwork = 3 + 5*n
286
 
          else
287
 
            lwork = 1 + 2*n
288
 
            liwork = 1
289
 
          endif
290
 
        else
291
 
          nb = ilaenv(1,'DSYTRD','U',n,-1,-1,-1)
292
 
          if (NoExpert) then
293
 
            lwork = (nb+2)*n
294
 
            liwork = 1
295
 
          else
296
 
            lwork = max(8*n,(nb+3)*n)
297
 
            liwork = 5*n
298
 
          endif
299
 
        endif
300
 
#ifdef MPI
301
 
      else
302
 
        if (Use2D) then
303
 
          call blacs_gridinfo(desc_h2d(2),nprow,npcol,myrow,mycol)
304
 
        else
305
 
          call blacs_gridinfo(desch(2),nprow,npcol,myrow,mycol)
306
 
        endif
307
 
        if (DivideConquer) then
308
 
          np0 = numroc(n,BlockSize,0,0,nprow)
309
 
          mq0 = numroc(n,BlockSize,0,0,npcol)
310
 
          lwork = max(BlockSize*(np0+1),3*BlockSize)
311
 
          lwork2 = BlockSize*(2*np0 + mq0 + BlockSize)
312
 
          lwork = max(lwork,lwork2)
313
 
          iarow = indxg2p(1,BlockSize,myrow,desch(7),nprow)
314
 
          iacol = indxg2p(1,BlockSize,mycol,desch(8),npcol)
315
 
          np = numroc(n,BlockSize,myrow,iarow,nprow)
316
 
          nq = numroc(n,BlockSize,mycol,iacol,npcol)
317
 
          nt = 3*n + max(BlockSize*(np+1),3*BlockSize)
318
 
          lwork2 = max(1+6*n+2*np*nq,nt) + 2*n
319
 
          lwork = max(lwork,lwork2)
320
 
          liwork = 7*n + 8*Nodes + 2
321
 
        else
322
 
          nn = max(n,BlockSize)
323
 
          nn = max(nn,2)
324
 
          np0 = numroc(nn,BlockSize,0,0,nprow)
325
 
          mq0 = numroc(nn,BlockSize,0,0,npcol)
326
 
          if (neigvec.gt.0) then
327
 
            lwork = 5*n + max(5*nn,np0*mq0+2*BlockSize*BlockSize) +
328
 
     &              iceil(neigvec,Nodes)*nn + maxclustersize*n
329
 
            anb = pjlaenv(ictxt,3,'PDSYTTRD','L',0,0,0,0)
330
 
            sqnpc = int(sqrt(dble(Nodes)))
331
 
            nps = max(numroc(n,1,0,0,sqnpc),2*anb)
332
 
            nsytrd_lwopt = n + 2*(anb + 1)*(4*nps + 2) + (nps + 3)*nps
333
 
            nsygst_lwopt = (2*np0 + mq0)*BlockSize + BlockSize*BlockSize
334
 
            lwork2 = max(5*n + nsytrd_lwopt,nsygst_lwopt)
335
 
            lwork = max(lwork,lwork2)
336
 
          else
337
 
            lwork = 5*n + max(5*nn,BlockSize*(np0+1))
338
 
          endif
339
 
          liwork = 6*max(n,Nodes+1,4)
340
 
        endif
341
 
#endif
342
 
      endif
343
 
 
344
 
C Scale memory by memory factor
345
 
      lwork = nint(MemoryFactor*dble(lwork))
346
 
 
347
 
C Allocate workspace arrays
348
 
      call re_alloc( work, 1, lwork, 'work', 'rdiag' )
349
 
      call re_alloc( iwork, 1, liwork, 'iwork', 'rdiag' )
350
 
      call re_alloc( ifail, 1, n, 'ifail', 'rdiag' )
351
 
#ifdef MPI
352
 
      call re_alloc( gap, 1, Nodes, 'gap', 'rdiag' )
353
 
      call re_alloc( iclustr, 1, 2*Nodes, 'iclustr', 'rdiag' )
354
 
 
355
 
      if (Use2D) then
356
 
C       Set up workspace arrays for 2D versions of 1D arrays
357
 
        call re_alloc( h2d, 1, mat_2d_row, 1, mat_2d_col, 'h2d',
358
 
     &                 'rdiag' )
359
 
        call re_alloc( s2d, 1, mat_2d_row, 1, mat_2d_col, 's2d',
360
 
     &                 'rdiag' )
361
 
        call re_alloc( z2d, 1, mat_2d_row, 1, mat_2d_col, 'z2d',
362
 
     &                 'rdiag' )
363
 
 
364
 
C For 2D case, copy arrays to new distribution
365
 
        call pdgemr2d(n, n, H, 1, 1, desch, h2d, 1, 1, desc_h2d, ictxt)
366
 
        call pdgemr2d(n, n, S, 1, 1, desch, s2d, 1, 1, desc_h2d, ictxt)
367
 
      endif
368
 
#ifdef SCALAPACK_DEBUG
369
 
      if ( .not. (Serial .or. debugged) ) then
370
 
      debugged = .true.
371
 
      d_lwork = -1
372
 
      d_liwork = -1
373
 
      if (DivideConquer) then
374
 
         if (Use2D) then
375
 
            call pdsyevd(jobz,'U',n,h2d,1,1,desc_h2d,w,z2d,1,1,
376
 
     &           desc_h2d,work,d_lwork,iwork,d_liwork,info)
377
 
         else
378
 
            call pdsyevd(jobz,'U',n,H,1,1,desch,w,Z,1,1,desch,work,
379
 
     &           d_lwork,iwork,d_liwork,info)
380
 
         endif
381
 
      else
382
 
         if (Use2D) then
383
 
            call pdsyevx(jobz,range,'U',n,h2d,1,1,desc_h2d,vl,vu,1,
384
 
     &           neigvec,abstol,neigok,nz,w,orfac,z2d,1,1,
385
 
     &           desc_h2d,work,d_lwork,iwork,d_liwork,ifail,
386
 
     &           iclustr,gap,info)
387
 
         else
388
 
            call pdsyevx(jobz,range,'U',n,H,1,1,desch,vl,vu,1,neigvec,
389
 
     &           abstol,neigok,nz,w,orfac,Z,1,1,desch,work,
390
 
     &           d_lwork,iwork,d_liwork,ifail,iclustr,gap,info)
391
 
         endif
392
 
      endif
393
 
      d_lwork  = nint(work(1))
394
 
      d_liwork = iwork(1)
395
 
      write(*,'(a,i0,4(a,i10))')'rdiag-debug: Node=',Node,
396
 
     &     ', lwork=', lwork,'>= lworkq=',d_lwork,
397
 
     &     ', liwork=',liwork,'>= liworkq=',d_liwork
398
 
      endif
399
 
#endif
400
 
 
401
 
#endif
402
 
 
403
 
      if (AllInOne) then
404
 
C*******************************************************************************
405
 
C Perform diagonalisation using simple driver                                  *
406
 
C*******************************************************************************
407
 
        if (Serial) then
408
 
          if (NoExpert) then
409
 
            call dsygv(1,jobz,'U',n,H,n,S,n,w,work,lwork,info)
410
 
            neigok = n
411
 
            call dcopy(n*n,H,1,Z,1)
412
 
          else
413
 
            call dsygvx(1,jobz,range,'U',n,H,n,S,n,vl,vu,1,neigvec,
414
 
     &                  abstol,neigok,w,Z,n,work,lwork,iwork,ifail,
415
 
     &                  info)
416
 
          endif
417
 
#ifdef MPI
418
 
        else 
419
 
          if (Use2D) then
420
 
            call pdsygvx(1,jobz,range,'U',n,h2d,1,1,desc_h2d,s2d,1,1,
421
 
     &                   desc_h2d,vl,vu,1,neigvec,abstol,neigok,nz,w,
422
 
     &                   orfac,z2d,1,1,desc_h2d,work,lwork,iwork,liwork,
423
 
     &                   ifail,iclustr,gap,info)
424
 
            call pdgemr2d(n,n,z2d,1,1,desc_h2d,Z,1,1,desch,ictxt)
425
 
          else
426
 
            call pdsygvx(1,jobz,range,'U',n,H,1,1,desch,S,1,1,desch,
427
 
     &                   vl,vu,1,neigvec,abstol,neigok,nz,w,orfac,Z,
428
 
     &                   1,1,desch,work,lwork,iwork,liwork,ifail,
429
 
     &                   iclustr,gap,info)
430
 
          endif
431
 
 
432
 
C If there is insufficient memory due to eigenvalue clustering increase memory
433
 
          if (info.eq.2) then
434
 
            oldmaxclustersize = maxclustersize
435
 
            do nc = 1,Nodes
436
 
              clustersize = iclustr(2*nc) - iclustr(2*nc-1)
437
 
              maxclustersize = max(maxclustersize,clustersize)
438
 
            enddo
439
 
            if (maxclustersize.gt.oldmaxclustersize) then
440
 
C If the memory has increased then try again - otherwise fail
441
 
              ierror = - 1
442
 
              goto 999
443
 
            endif
444
 
          endif
445
 
 
446
 
#endif
447
 
        endif
448
 
 
449
 
C Check error flag
450
 
        if (info.ne.0) then
451
 
          ierror = 1
452
 
          if (info.lt.0) then
453
 
            call die('Illegal argument to general eigensolver')
454
 
          elseif (info.gt.0)   then
455
 
            if (mod(info/2,2).ne.0) then
456
 
              if (Node.eq.0) then
457
 
                write(6,'(/,''Clustered eigenvectors not converged - '',
458
 
     &            ''more memory required'',/)')
459
 
              endif
460
 
            endif
461
 
            call die('Failure to converge general eigenproblem')
462
 
          endif
463
 
        endif
464
 
        if (neigok.lt.neigvec) then
465
 
          call die('Insufficient eigenvalues converged in rdiag')
466
 
        endif
467
 
 
468
 
      else
469
 
C*******************************************************************************
470
 
C Factorise overlap matrix                                                     *
471
 
C*******************************************************************************
472
 
        call timer('rdiag1',1)
473
 
        if (Serial) then
474
 
          call dpotrf('U',n,S,n,info)
475
 
#ifdef MPI
476
 
        else
477
 
          if (Use2D) then
478
 
            call pdpotrf('U',n,s2d,1,1,desc_h2d,info)
479
 
          else
480
 
            call pdpotrf('U',n,S,1,1,desch,info)
481
 
          endif
482
 
#endif
483
 
        endif
484
 
        if (info.ne.0) then
485
 
          call die('Error in Cholesky factorisation in rdiag')
486
 
        endif
487
 
        call timer('rdiag1',2)
488
 
 
489
 
C*******************************************************************************
490
 
C Transform problem to standard eigenvalue problem                             *
491
 
C*******************************************************************************
492
 
        call timer('rdiag2',1)
493
 
        if (Serial) then
494
 
          call dsygst(1,'U',n,H,n,S,n,info)
495
 
#ifdef MPI
496
 
        else
497
 
          if (Use2D) then
498
 
            call pdsyngst(1,'U',n,h2d,1,1,desc_h2d,s2d,1,1,
499
 
     &                    desc_h2d,dscale,work,lwork,info)
500
 
          else
501
 
            call pdsyngst(1,'U',n,H,1,1,desch,S,1,1,
502
 
     &                    desch,dscale,work,lwork,info)
503
 
          endif
504
 
#endif
505
 
        endif
506
 
        if (info.ne.0) then
507
 
          call die('Error in forward transformation in rdiag')
508
 
        endif
509
 
        call timer('rdiag2',2)
510
 
 
511
 
C*******************************************************************************
512
 
C Pre-rotate using trial eigenvectors                                          *
513
 
C*******************************************************************************
514
 
        if (PreRotate.and.ChangeAlgorithm) then
515
 
          if (Serial) then
516
 
C Rotate according to eigenvectors from previous cycle
517
 
            call dsymm('L','U',n,n,one,H,n,Zsave,n,zero,Z,n)
518
 
            call dgemm('T','N',n,n,n,one,Zsave,n,Z,n,zero,H,n)
519
 
#ifdef MPI
520
 
          else
521
 
            if (Use2D) then
522
 
              call pdsymm('L','U',n,n,one,h2d,1,1,desc_h2d,Zsave,1,1,
523
 
     &                     desc_h2d,zero,z2d,1,1,desc_h2d)
524
 
              call pdgemm('T','N',n,n,n,one,Zsave,1,1,desc_h2d,z2d,1,
525
 
     &                     1,desch,zero,h2d,1,1,desc_h2d)
526
 
            else
527
 
              call pdsymm('L','U',n,n,one,H,1,1,desch,Zsave,1,1,desch,
528
 
     &                     zero,Z,1,1,desch)
529
 
              call pdgemm('T','N',n,n,n,one,Zsave,1,1,desch,Z,1,1,
530
 
     &                     desch,zero,H,1,1,desch)
531
 
            endif
532
 
#endif
533
 
          endif
534
 
        endif
535
 
 
536
 
C*******************************************************************************
537
 
C Solve standard eigenvalue problem                                            *
538
 
C*******************************************************************************
539
 
        call timer('rdiag3',1)
540
 
        if (Serial) then
541
 
          if (DivideConquer) then
542
 
            call dsyevds(jobz,'U',n,H,n,w,Z,n,work,lwork,iwork,liwork,
543
 
     &                   info)
544
 
            neigok = n
545
 
          else
546
 
            call dsyevx(jobz,range,'U',n,H,n,vl,vu,1,neigvec,abstol,
547
 
     &                  neigok,w,Z,n,work,lwork,iwork,ifail,info)
548
 
          endif
549
 
#ifdef MPI
550
 
        else
551
 
          if (DivideConquer) then
552
 
            if (Use2D) then
553
 
              call pdsyevd(jobz,'U',n,h2d,1,1,desc_h2d,w,z2d,1,1,
554
 
     &                     desc_h2d,work,lwork,iwork,liwork,info)
555
 
            else
556
 
              call pdsyevd(jobz,'U',n,H,1,1,desch,w,Z,1,1,desch,work,
557
 
     &                     lwork,iwork,liwork,info)
558
 
            endif
559
 
            neigok = n
560
 
          else
561
 
            if (Use2D) then
562
 
              call pdsyevx(jobz,range,'U',n,h2d,1,1,desc_h2d,vl,vu,1,
563
 
     &                     neigvec,abstol,neigok,nz,w,orfac,z2d,1,1,
564
 
     &                     desc_h2d,work,lwork,iwork,liwork,ifail,
565
 
     &                     iclustr,gap,info)
566
 
            else
567
 
              call pdsyevx(jobz,range,'U',n,H,1,1,desch,vl,vu,1,neigvec,
568
 
     &                     abstol,neigok,nz,w,orfac,Z,1,1,desch,work,
569
 
     &                     lwork,iwork,liwork,ifail,iclustr,gap,info)
570
 
            endif
571
 
 
572
 
C If there is insufficient memory due to eigenvalue clustering increase memory
573
 
            if (info.eq.2) then
574
 
              oldmaxclustersize = maxclustersize
575
 
              do nc = 1,Nodes 
576
 
                clustersize = iclustr(2*nc) - iclustr(2*nc-1)
577
 
                maxclustersize = max(maxclustersize,clustersize)
578
 
              enddo
579
 
              if (maxclustersize.gt.oldmaxclustersize) then
580
 
C If the memory has increased then try again - otherwise fail
581
 
                ierror = - 1
582
 
                call timer('rdiag3',2)
583
 
                goto 999
584
 
              endif
585
 
            endif
586
 
 
587
 
          endif
588
 
#endif
589
 
        endif
590
 
 
591
 
C Check error flag
592
 
        if (info.ne.0) then
593
 
          ierror = 1
594
 
          if (info.lt.0) then
595
 
            call die('Illegal argument to standard eigensolver')
596
 
          elseif (info.gt.0)   then
597
 
            if (mod(info/2,2).ne.0) then
598
 
              if (Node.eq.0) then
599
 
                write(6,'(/,''Clustered eigenvectors not converged - '',
600
 
     &            ''more memory required'',/)')
601
 
              endif
602
 
            endif
603
 
            call die('Failure to converge standard eigenproblem')
604
 
          endif
605
 
        endif
606
 
        if (neigok.lt.neigvec) then
607
 
          call die('Insufficient eigenvalues converged in rdiag')
608
 
        endif
609
 
 
610
 
        call timer('rdiag3',2)
611
 
 
612
 
C*******************************************************************************
613
 
C Post-rotate using trial eigenvectors                                         *
614
 
C*******************************************************************************
615
 
        if (PreRotate.and.ChangeAlgorithm) then
616
 
          if (Serial) then
617
 
            call dgemm('N','N',n,n,n,one,Zsave,n,Z,n,zero,H,n)
618
 
            call dcopy(n*nm,H(1,1),1,Z(1,1),1)
619
 
#ifdef MPI
620
 
          else
621
 
            if (Use2D) then
622
 
              call pdgemm('N','N',n,n,n,one,Zsave,1,1,desc_h2d,z2d,1,
623
 
     &                     1,desc_h2d,zero,h2d,1,1,desc_h2d)
624
 
              call dcopy(n*nm,h2d(1,1),1,z2d(1,1),1)
625
 
            else
626
 
              call pdgemm('N','N',n,n,n,one,Zsave,1,1,desch,Z,1,1,
627
 
     &                     desch,zero,H,1,1,desch)
628
 
              call dcopy(n*nm,H(1,1),1,Z(1,1),1)
629
 
            endif
630
 
#endif
631
 
          endif
632
 
        endif
633
 
 
634
 
C Save eigenvectors if required
635
 
        if (SaveEigenvectors) then
636
 
#ifdef MPI
637
 
          if (Use2D) then
638
 
            call dcopy(n*nm,z2d(1,1),1,Zsave(1,1),1)
639
 
          else
640
 
#endif
641
 
            call dcopy(n*nm,Z(1,1),1,Zsave(1,1),1)
642
 
#ifdef MPI
643
 
          endif
644
 
#endif
645
 
        endif
646
 
 
647
 
C*******************************************************************************
648
 
C Back transformation                                                          *
649
 
C*******************************************************************************
650
 
        call timer('rdiag4',1)
651
 
        if (Serial) then
652
 
          if (neigvec.gt.0) then
653
 
            call dtrsm('Left','U','N','Non-unit',n,neigvec,one,S,n,Z,n)
654
 
          endif
655
 
#ifdef MPI
656
 
        else
657
 
          if (neigvec.gt.0) then
658
 
            if (Use2D) then
659
 
              call pdtrsm('Left','U','N','Non-unit',n,neigvec,one,
660
 
     &                     s2d,1,1,desc_h2d,z2d,1,1,desc_h2d)
661
 
              call pdgemr2d(n,n,z2d,1,1,desc_h2d,Z,1,1,desch,ictxt)
662
 
            else
663
 
              call pdtrsm('Left','U','N','Non-unit',n,neigvec,one,
664
 
     &                     S,1,1,desch,Z,1,1,desch)
665
 
            endif
666
 
            if (dscale.ne.one) then
667
 
              call dscal(n,dscale,w,1)
668
 
            endif
669
 
          endif
670
 
#endif
671
 
        endif
672
 
        if (info.ne.0) then
673
 
          call die('Error in back transformation in rdiag')
674
 
        endif
675
 
        call timer('rdiag4',2)
676
 
      endif
677
 
 
678
 
C*******************************************************************************
679
 
C Clean up                                                                     *
680
 
C*******************************************************************************
681
 
 
682
 
C Common exit point 
683
 
  999 continue
684
 
 
685
 
C Deallocate workspace arrays
686
 
#ifdef MPI
687
 
      if (associated(Zsave)) call de_alloc( Zsave, 'Zsave', 'rdiag' )
688
 
      if (Use2D) then
689
 
        call de_alloc( h2d, 'h2d', 'rdiag' )
690
 
        call de_alloc( s2d, 's2d', 'rdiag' )
691
 
        call de_alloc( z2d, 'z2d', 'rdiag' )
692
 
      endif
693
 
      call de_alloc( iclustr, 'iclustr', 'rdiag' )
694
 
      call de_alloc( gap, 'gap', 'rdiag' )
695
 
#endif
696
 
      call de_alloc( ifail, 'ifail', 'rdiag' )
697
 
      call de_alloc( iwork, 'iwork', 'rdiag' )
698
 
      call de_alloc( work, 'work', 'rdiag' )
699
 
 
700
 
C  Exit point, excluding deallocations
701
 
1000  continue
702
 
 
703
 
C  Restore old allocation defaults
704
 
      call alloc_default( restore=oldDefaults )
705
 
 
706
 
C Set first call flag to false
707
 
      FirstCall = .false.
708
 
 
709
 
C Stop time count
710
 
      call timer('rdiag',2)
711
 
 
712
 
      end