Line data Source code
1 : !!****m* ABINIT/m_rayleigh_ritz
2 : !! NAME
3 : !! m_rayleigh_ritz
4 : !!
5 : !! FUNCTION
6 : !! This file contains routines that perform the Rayleigh-Ritz,
7 : !! either by forming the full matrix (_subdiago) or by forming the
8 : !! distributed matrix in block-cyclic form (_distributed)
9 : !!
10 : !! COPYRIGHT
11 : !! Copyright (C) 2014-2026 ABINIT group (AL)
12 : !! This file is distributed under the terms of the
13 : !! GNU General Public License, see ~abinit/COPYING
14 : !! or http://www.gnu.org/copyleft/gpl.txt .
15 : !!
16 : !! SOURCE
17 :
18 : #if defined HAVE_CONFIG_H
19 : #include "config.h"
20 : #endif
21 :
22 : #include "abi_common.h"
23 :
24 : module m_rayleigh_ritz
25 :
26 : use defs_basis
27 : use m_errors
28 : use m_cgtools
29 : use m_xmpi
30 : use m_abicore
31 : use m_abi_linalg
32 : use m_slk
33 :
34 : use defs_abitypes, only : mpi_type
35 : use m_time, only : timab
36 : use m_numeric_tools, only : pack_matrix
37 :
38 : implicit none
39 :
40 : private
41 : !!***
42 :
43 : public :: rayleigh_ritz_subdiago
44 : #if defined HAVE_LINALG_SCALAPACK
45 : public :: rayleigh_ritz_distributed
46 : #endif
47 : !!***
48 :
49 : contains
50 : !!***
51 :
52 : !!****f* ABINIT/rayleigh_ritz_subdiago
53 : !! NAME
54 : !! rayleigh_ritz_subdiago
55 : !!
56 : !! FUNCTION
57 : !! Performs a rayleigh-ritz procedure (subspace rotation), building the
58 : !! hamiltonian/overlap matrices in full and calling the subdiago method
59 : !!
60 : !! INPUTS
61 : !! mpi_enreg=information about MPI parallelization
62 : !! nband=number of bands at this k point for that spin polarization
63 : !! npw=number of plane waves at this k point
64 : !! nspinor=number of plane waves at this k point
65 : !! usepaw=if 1 we use the PAW method
66 : !!
67 : !! OUTPUT
68 : !! eig(nband)=array for holding eigenvalues (hartree)
69 : !!
70 : !! SIDE EFFECTS
71 : !! cg(2,*)=updated wavefunctions
72 : !! ghc(2,*)=updated ghc
73 : !! gsc(2,*)=updated gsc
74 : !! gvnlxc(2,*)=updated gvnlxc
75 : !!
76 : !! NOTES
77 : !! TODO choose generalized eigenproblem or ortho + diago (see #if 1)
78 : !!
79 : !! SOURCE
80 :
81 48 : subroutine rayleigh_ritz_subdiago(cg,ghc,gsc,gvnlxc,eig,has_fock,istwf_k,mpi_enreg,nband,npw,nspinor,usepaw)
82 :
83 : ! Arguments
84 : type(mpi_type),intent(inout) :: mpi_enreg
85 : integer,intent(in) :: nband,npw,nspinor,usepaw,istwf_k
86 : real(dp),intent(inout) :: cg(2,npw*nspinor*nband),gsc(2,npw*nspinor*nband),ghc(2,npw*nspinor*nband),gvnlxc(2,npw*nspinor*nband)
87 : real(dp),intent(out) :: eig(nband)
88 : logical :: has_fock
89 :
90 : ! Locals
91 48 : real(dp), allocatable :: subham(:), totham(:,:)
92 48 : real(dp), allocatable :: subovl(:), totovl(:,:)
93 48 : real(dp), allocatable :: evec(:,:), edummy(:,:)
94 : integer :: ierr, cplx, vectsize
95 96 : real(dp) :: gtempc(2,npw*nspinor*nband), tsec(2)
96 : character :: blas_transpose
97 :
98 : integer, parameter :: timer_chebfi = 1600, timer_alltoall = 1601, timer_apply_inv_ovl = 1602, timer_rotation = 1603
99 : integer, parameter :: timer_subdiago = 1604, timer_subham = 1605, timer_ortho = 1606, timer_getghc = 1607
100 : integer, parameter :: timer_residuals = 1608, timer_update_eigen = 1609, timer_sync = 1610
101 :
102 : ! *************************************************************************
103 :
104 48 : if(istwf_k == 1) then
105 48 : cplx = 2
106 48 : vectsize = npw*nspinor
107 48 : blas_transpose = 'c'
108 : else
109 0 : cplx = 1
110 0 : vectsize = 2*npw*nspinor
111 0 : blas_transpose = 't'
112 : end if
113 :
114 : #if 1
115 48 : call timab(timer_subham, 1, tsec)
116 :
117 : ! Transform cg, ghc and maybe gsc, according to istwf_k
118 48 : if(istwf_k == 2) then
119 0 : cg = cg * sqrt2
120 0 : if(mpi_enreg%me_g0 == 1) cg(:, 1:npw*nspinor*nband:npw) = cg(:, 1:npw*nspinor*nband:npw) / sqrt2
121 0 : ghc = ghc * sqrt2
122 0 : if(mpi_enreg%me_g0 == 1) ghc(:, 1:npw*nspinor*nband:npw) = ghc(:, 1:npw*nspinor*nband:npw) / sqrt2
123 0 : if(usepaw == 1) then
124 0 : gsc = gsc * sqrt2
125 0 : if(mpi_enreg%me_g0 == 1) gsc(:, 1:npw*nspinor*nband:npw) = gsc(:, 1:npw*nspinor*nband:npw) / sqrt2
126 : end if
127 : end if
128 :
129 : ! Build, pack and sum suham
130 144 : ABI_MALLOC(subham, (cplx*nband*(nband+1)/2))
131 192 : ABI_MALLOC(totham, (cplx, nband*nband))
132 : call abi_xgemm(blas_transpose,'n',nband,nband,vectsize,cone,ghc,vectsize,&
133 48 : & cg,vectsize,czero,totham,nband, x_cplx=cplx)
134 48 : call pack_matrix(totham, subham, nband, cplx)
135 48 : ABI_FREE(totham)
136 48 : call xmpi_sum(subham,mpi_enreg%comm_bandspinorfft,ierr)
137 :
138 :
139 : ! Same for subovl
140 96 : ABI_MALLOC(subovl, (cplx*nband*(nband+1)/2))
141 144 : ABI_MALLOC(totovl, (cplx, nband*nband))
142 48 : if(usepaw == 1) then
143 : call abi_xgemm(blas_transpose,'n',nband,nband,vectsize,cone,gsc,vectsize,&
144 48 : & cg,vectsize,czero,totovl,nband, x_cplx=cplx)
145 : else
146 : call abi_xgemm(blas_transpose,'n',nband,nband,vectsize,cone,cg,vectsize,&
147 0 : & cg,vectsize,czero,totovl,nband, x_cplx=cplx)
148 : end if
149 48 : call pack_matrix(totovl, subovl, nband, cplx)
150 48 : ABI_FREE(totovl)
151 48 : call xmpi_sum(subovl,mpi_enreg%comm_bandspinorfft,ierr)
152 :
153 :
154 : ! Transform back
155 48 : if(istwf_k == 2) then
156 0 : cg = cg / sqrt2
157 0 : if(mpi_enreg%me_g0 == 1) cg(:, 1:npw*nspinor*nband:npw) = cg(:, 1:npw*nspinor*nband:npw) * sqrt2
158 0 : ghc = ghc / sqrt2
159 0 : if(mpi_enreg%me_g0 == 1) ghc(:, 1:npw*nspinor*nband:npw) = ghc(:, 1:npw*nspinor*nband:npw) * sqrt2
160 0 : if(usepaw == 1) then
161 0 : gsc = gsc / sqrt2
162 0 : if(mpi_enreg%me_g0 == 1) gsc(:, 1:npw*nspinor*nband:npw) = gsc(:, 1:npw*nspinor*nband:npw) * sqrt2
163 : end if
164 : end if
165 48 : call timab(timer_subham, 2, tsec)
166 :
167 :
168 48 : call timab(timer_subdiago, 1, tsec)
169 192 : ABI_MALLOC(evec, (cplx*nband, nband))
170 :
171 48 : call abi_xhpgv(1,'V','U',nband,subham,subovl,eig,evec,nband,istwf_k=istwf_k,use_slk=mpi_enreg%paral_kgb)
172 :
173 48 : ABI_FREE(subham)
174 48 : ABI_FREE(subovl)
175 :
176 : ! Fix the phase (this is because of the simultaneous diagonalisation of this
177 : ! matrix by different processors, allowing to get different unitary transforms, thus breaking the
178 : ! coherency of parts of cg stored on different processors).
179 : ! call cg_normev(evec,nband,nband) ! Unfortunately, for cg_normev to work, one needs the vectors to be normalized, so uses fxphas_seq
180 144 : ABI_MALLOC(edummy, (cplx*nband, nband))
181 48 : call fxphas_seq(evec,edummy,0,0,1,nband*nband,nband*nband,nband,nband,0)
182 48 : ABI_FREE(edummy)
183 :
184 : ! Rotate
185 48 : call abi_xgemm('n','n',vectsize,nband, nband,cone,cg , vectsize, evec, nband, czero, gtempc, vectsize, x_cplx=cplx)
186 111936 : cg = gtempc
187 48 : call abi_xgemm('n','n',vectsize,nband, nband,cone,ghc, vectsize, evec, nband, czero, gtempc, vectsize, x_cplx=cplx)
188 111936 : ghc = gtempc
189 48 : if(usepaw == 1) then
190 48 : call abi_xgemm('n','n',vectsize,nband, nband,cone,gsc, vectsize, evec, nband, czero, gtempc, vectsize, x_cplx=cplx)
191 111936 : gsc = gtempc
192 : endif
193 48 : if(usepaw==0 .or. has_fock)then
194 0 : call abi_xgemm('n','n',vectsize,nband, nband,cone,gvnlxc, vectsize, evec, nband, czero, gtempc, vectsize, x_cplx=cplx)
195 48 : gvnlxc = gtempc
196 : end if
197 48 : ABI_FREE(evec)
198 48 : call timab(timer_subdiago, 2, tsec)
199 :
200 : #else
201 : !! TODO non-functional, should be rewritten. Possibly faster (tests needed)
202 : call wrtout(std_out, 'Transposed, orthogonalizing')
203 :
204 : ! orthonormalization
205 : call timab(timer_ortho, 1, tsec)
206 : if (usepaw==1) then
207 : call abi_xorthonormalize(cg, gsc,nband, mpi_enreg%comm_bandspinorfft, sqgram, npw*nspinor, 2)
208 : else
209 : call abi_xorthonormalize(cg, cg, nband, mpi_enreg%comm_bandspinorfft, sqgram, npw*nspinor, 2)
210 : end if
211 : call timab(timer_ortho, 2, tsec)
212 :
213 : ! rotate ghc, gsc and gvnlxc
214 : call timab(timer_rotation, 1, tsec)
215 : call abi_xtrsm('r','u','n','n',npw*nspinor,nband,cone,sqgram,nband, ghc,npw*nspinor,x_cplx=2)
216 : if(usepaw==1) then
217 : call abi_xtrsm('r','u','n','n',npw*nspinor,nband,cone,sqgram,nband, gsc,npw*nspinor,x_cplx=2)
218 : endif
219 : if(usepaw==0 .or has_fock)then
220 : call abi_xtrsm('r','u','n','n',npw*nspinor,nband,cone,sqgram,nband, gvnlxc,npw*nspinor,x_cplx=2)
221 : end if
222 : call timab(timer_rotation, 2, tsec)
223 :
224 : call wrtout(std_out, 'Orthogonalized, building subham')
225 :
226 : ! build hamiltonian in subspace
227 : call timab(timer_subham, 1, tsec)
228 : call abi_xgemm(blas_transpose,'n',nband,nband,npw*nspinor,cone,ghc,npw*nspinor,&
229 : & cg,npw*nspinor,czero,totham,nband, x_cplx=2)
230 : ! pack for compatibility with subdiago
231 : call pack_matrix(totham, subham, nband)
232 : call xmpi_sum(subham,mpi_enreg%comm_bandspinorfft,ierr)
233 : call timab(timer_subham, 2, tsec)
234 :
235 : call wrtout(std_out, 'Subham built, diagonalizing')
236 :
237 : ! Rayleigh-Ritz
238 : call timab(timer_subdiago,1,tsec)
239 : call subdiago(cg,eig,evec,gsc,0,0,gs_hamk%istwf_k,&
240 : & mcg,mcg,nband,npw,nspinor,dtset%paral_kgb,&
241 : & subham,dummy,0,gs_hamk%usepaw,mpi_enreg%me_g0)
242 : call timab(timer_subdiago,2,tsec)
243 :
244 : call wrtout(std_out, 'Diagonalization done')
245 :
246 : ! Rotate ghc and gvnlxc according to evecs
247 : call timab(timer_rotation, 1, tsec)
248 : call abi_xgemm('n','n',npw*nspinor,nband, nband,cone,ghc, npw*nspinor, evec, nband, czero, gtempc, npw*nspinor, x_cplx=2)
249 : ghc = gtempc
250 : if(usepaw==0 .or has_fock)then
251 : call abi_xgemm('n','n',npw*nspinor,nband, nband,cone,gvnlxc, npw*nspinor, evec, nband, czero, gtempc, npw*nspinor, x_cplx=2)
252 : gvnlxc = gtempc
253 : end if
254 : call timab(timer_rotation, 2, tsec)
255 :
256 : #endif
257 :
258 96 : end subroutine rayleigh_ritz_subdiago
259 : !!***
260 :
261 : #if defined HAVE_LINALG_SCALAPACK
262 : !!****f* ABINIT/rayleigh_ritz_distributed
263 : !! NAME
264 : !! rayleigh_ritz_distributed
265 : !!
266 : !! FUNCTION
267 : !! Performs a rayleigh-ritz procedure (subspace rotation), building the distributed
268 : !! hamiltonian/overlap matrices directly, and calling the ScaLapack routines
269 : !!
270 : !! INPUTS
271 : !! mpi_enreg=information about MPI parallelization
272 : !! nband=number of bands at this k point for that spin polarization
273 : !! npw=number of plane waves at this k point
274 : !! nspinor=number of plane waves at this k point
275 : !! usepaw=do we use the PAW method
276 : !!
277 : !! OUTPUT
278 : !! eig(nband)=array for holding eigenvalues (hartree)
279 : !!
280 : !! SIDE EFFECTS
281 : !! cg(2,*)=updated wavefunctions
282 : !! ghc(2,*)=updated ghc
283 : !! gsc(2,*)=updated gsc
284 : !! gvnlxc(2,*)=updated gvnlxc
285 : !!
286 : !! NOTES
287 : !! Should profile for large test cases and see where the bottleneck is.
288 : !! Is it the copies? Should we do partial GEMMs?
289 : !! Is it the latency? Should we buffer more?
290 : !! Should we overlap computations and communications? (easy in theory, tedious in practice)
291 : !!
292 : !! SOURCE
293 :
294 : subroutine rayleigh_ritz_distributed(cg,ghc,gsc,gvnlxc,eig,has_fock,istwf_k,mpi_enreg,nband,npw,nspinor,usepaw)
295 :
296 : integer,external :: NUMROC
297 :
298 : ! Arguments
299 : type(mpi_type),intent(inout) :: mpi_enreg
300 : integer,intent(in) :: nband,npw,nspinor,usepaw,istwf_k
301 : real(dp),intent(inout) :: cg(2,npw*nspinor*nband),gsc(2,npw*nspinor*nband),ghc(2,npw*nspinor*nband),gvnlxc(2,npw*nspinor*nband)
302 : real(dp),intent(out) :: eig(nband)
303 : logical :: has_fock
304 :
305 : ! Locals
306 : integer :: blocksize,nbproc,iproc,ierr,cplx,vectsize
307 : integer :: buffsize_iproc(2), coords_iproc(2), grid_dims(2)
308 : real(dp) :: cg_new(2,npw*nspinor*nband),gsc_or_vnlxc_new(2,npw*nspinor*nband),ghc_new(2,npw*nspinor*nband)
309 : real(dp), allocatable :: ham_iproc(:,:), ovl_iproc(:,:), evec_iproc(:,:), left_temp(:,:), right_temp(:,:)
310 : real(dp) :: tsec(2)
311 : type(slkmat_dp_t) :: sca_ham, sca_ovl, sca_evec
312 : !character(len=500) :: message
313 : character :: blas_transpose
314 :
315 : integer, parameter :: timer_chebfi = 1600, timer_alltoall = 1601, timer_apply_inv_ovl = 1602, timer_rotation = 1603
316 : integer, parameter :: timer_subdiago = 1604, timer_subham = 1605, timer_ortho = 1606, timer_getghc = 1607
317 : integer, parameter :: timer_residuals = 1608, timer_update_eigen = 1609, timer_sync = 1610
318 :
319 : ! *************************************************************************
320 :
321 : if(istwf_k == 1) then
322 : cplx = 2
323 : vectsize = npw*nspinor
324 : blas_transpose = 'c'
325 : else
326 : cplx = 1
327 : vectsize = 2*npw*nspinor
328 : blas_transpose = 't'
329 : end if
330 :
331 : !write(message, *) 'RR: init'
332 : !call wrtout(std_out,message)
333 : !======================================================================================================
334 : ! Init Scalapack matrices
335 : !======================================================================================================
336 : call sca_ham%init(nband,nband,slk_processor,istwf_k)
337 : call sca_ovl%init(nband,nband,slk_processor,istwf_k)
338 : call sca_evec%init(nband,nband,slk_processor,istwf_k)
339 :
340 : ! Get info
341 : blocksize = sca_ham%size_blocs(1) ! Assume square blocs
342 : nbproc = slk_processor%grid%nprocs
343 : grid_dims = slk_processor%grid%dims
344 :
345 : !======================================================================================================
346 : ! Build hamiltonian and overlap matrices
347 : !======================================================================================================
348 : ! TODO maybe we should avoid copies at the price of less BLAS efficiency (when blocksize is small)? must profile.
349 :
350 : call timab(timer_subham, 1, tsec)
351 :
352 : ! Transform cg, ghc and maybe gsc, according to istwf_k
353 : if(istwf_k == 2) then
354 : cg = cg * sqrt2
355 : if(mpi_enreg%me_g0 == 1) cg(:, 1:npw*nspinor*nband:npw) = cg(:, 1:npw*nspinor*nband:npw) / sqrt2
356 : ghc = ghc * sqrt2
357 : if(mpi_enreg%me_g0 == 1) ghc(:, 1:npw*nspinor*nband:npw) = ghc(:, 1:npw*nspinor*nband:npw) / sqrt2
358 : if(usepaw == 1) then
359 : gsc = gsc * sqrt2
360 : if(mpi_enreg%me_g0 == 1) gsc(:, 1:npw*nspinor*nband:npw) = gsc(:, 1:npw*nspinor*nband:npw) / sqrt2
361 : end if
362 : end if
363 :
364 : do iproc=0,nbproc-1
365 : ! Build the local matrix belonging to processor iproc
366 : !write(message, *) 'RR: build', iproc
367 : !call wrtout(std_out,message)
368 :
369 : ! Get coordinates of iproc
370 : coords_iproc(1) = INT(iproc / grid_dims(2))
371 : coords_iproc(2) = MOD(iproc, grid_dims(2))
372 :
373 : ! Get buffersize of iproc
374 : buffsize_iproc(1) = NUMROC(nband,blocksize,coords_iproc(1),0,slk_processor%grid%dims(1))
375 : buffsize_iproc(2) = NUMROC(nband,blocksize,coords_iproc(2),0,slk_processor%grid%dims(2))
376 :
377 : ! Allocate matrices_iproc, that will gather the contribution of this proc to the block owned by iproc
378 : ABI_MALLOC(ham_iproc, (cplx*buffsize_iproc(1), buffsize_iproc(2)))
379 : ABI_MALLOC(ovl_iproc, (cplx*buffsize_iproc(1), buffsize_iproc(2)))
380 :
381 : ! Build them
382 : ABI_MALLOC(left_temp, (2, npw*nspinor*buffsize_iproc(1)))
383 : ABI_MALLOC(right_temp, (2, npw*nspinor*buffsize_iproc(2)))
384 :
385 : ! ovl
386 : call from_mat_to_block_cyclic(cg, npw*nspinor, nband, left_temp, &
387 : & buffsize_iproc(1), blocksize, coords_iproc(1), grid_dims(1))
388 : if(usepaw == 1) then
389 : call from_mat_to_block_cyclic(gsc, npw*nspinor, nband, right_temp, &
390 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
391 : else
392 : call from_mat_to_block_cyclic(cg, npw*nspinor, nband, right_temp, &
393 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
394 : end if
395 : call abi_xgemm(blas_transpose,'n',buffsize_iproc(1),buffsize_iproc(2),vectsize,cone,left_temp,vectsize,&
396 : & right_temp,vectsize,czero,ovl_iproc,buffsize_iproc(1), x_cplx=cplx)
397 :
398 : ! ham
399 : call from_mat_to_block_cyclic(ghc, npw*nspinor, nband, right_temp, &
400 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
401 : call abi_xgemm(blas_transpose,'n',buffsize_iproc(1),buffsize_iproc(2),vectsize,cone,left_temp,vectsize,&
402 : & right_temp,vectsize,czero,ham_iproc,buffsize_iproc(1), x_cplx=cplx)
403 :
404 : ! Sum to iproc, and fill sca_ matrices
405 : call xmpi_sum_master(ham_iproc, iproc, slk_communicator, ierr)
406 : call xmpi_sum_master(ovl_iproc, iproc, slk_communicator, ierr)
407 : if(iproc == slk_processor%my_rank) then
408 : ! DCOPY to bypass the real/complex issue
409 : if(cplx == 2) then
410 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), ham_iproc, 1, sca_ham%buffer_cplx, 1)
411 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), ovl_iproc, 1, sca_ovl%buffer_cplx, 1)
412 : else
413 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), ham_iproc, 1, sca_ham%buffer_real, 1)
414 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), ovl_iproc, 1, sca_ovl%buffer_real, 1)
415 : end if
416 : end if
417 :
418 : ABI_FREE(ham_iproc)
419 : ABI_FREE(ovl_iproc)
420 : ABI_FREE(left_temp)
421 : ABI_FREE(right_temp)
422 : end do
423 :
424 : ! Final sum
425 : if(cplx == 2) then
426 : call xmpi_sum(sca_ham%buffer_cplx, slk_complement_communicator, ierr)
427 : call xmpi_sum(sca_ovl%buffer_cplx, slk_complement_communicator, ierr)
428 : else
429 : call xmpi_sum(sca_ham%buffer_real, slk_complement_communicator, ierr)
430 : call xmpi_sum(sca_ovl%buffer_real, slk_complement_communicator, ierr)
431 : end if
432 :
433 : ! Transform back
434 : if(istwf_k == 2) then
435 : cg = cg / sqrt2
436 : if(mpi_enreg%me_g0 == 1) cg(:, 1:npw*nspinor*nband:npw) = cg(:, 1:npw*nspinor*nband:npw) * sqrt2
437 : ghc = ghc / sqrt2
438 : if(mpi_enreg%me_g0 == 1) ghc(:, 1:npw*nspinor*nband:npw) = ghc(:, 1:npw*nspinor*nband:npw) * sqrt2
439 : if(usepaw == 1) then
440 : gsc = gsc / sqrt2
441 : if(mpi_enreg%me_g0 == 1) gsc(:, 1:npw*nspinor*nband:npw) = gsc(:, 1:npw*nspinor*nband:npw) * sqrt2
442 : end if
443 : end if
444 : call timab(timer_subham, 2, tsec)
445 :
446 : !======================================================================================================
447 : ! Do the diagonalization
448 : !======================================================================================================
449 : !write(message, *) 'RR: diag'
450 : !call wrtout(std_out,message)
451 : call timab(timer_subdiago, 1, tsec)
452 : call compute_generalized_eigen_problem(slk_processor,sca_ham,sca_ovl,&
453 : & sca_evec,eig,slk_communicator,istwf_k)
454 : call timab(timer_subdiago, 2, tsec)
455 :
456 : !======================================================================================================
457 : ! Perform rotation
458 : !======================================================================================================
459 : call timab(timer_rotation, 1, tsec)
460 : cg_new = zero
461 : gsc_or_vnlxc_new = zero
462 : ghc_new = zero
463 : do iproc=0,nbproc-1
464 : ! Compute the contribution to the rotated matrices from this block
465 : !write(message, *) 'RR: rot', iproc
466 : !call wrtout(std_out,message)
467 :
468 : ! Get coordinates of iproc
469 : coords_iproc(1) = INT(iproc / grid_dims(2))
470 : coords_iproc(2) = MOD(iproc, grid_dims(2))
471 :
472 : ! Get buffersize of iproc
473 : buffsize_iproc(1) = NUMROC(nband,blocksize,coords_iproc(1),0,slk_processor%grid%dims(1))
474 : buffsize_iproc(2) = NUMROC(nband,blocksize,coords_iproc(2),0,slk_processor%grid%dims(2))
475 :
476 : ! Get data from iproc
477 : ABI_MALLOC(evec_iproc, (cplx*buffsize_iproc(1), buffsize_iproc(2)))
478 : if(iproc == slk_processor%my_rank) then
479 : if(cplx == 2) then
480 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), sca_evec%buffer_cplx, 1, evec_iproc, 1)
481 : else
482 : call DCOPY(cplx*buffsize_iproc(1)*buffsize_iproc(2), sca_evec%buffer_real, 1, evec_iproc, 1)
483 : end if
484 : end if
485 : call xmpi_bcast(evec_iproc,iproc,slk_communicator,ierr)
486 :
487 : ! Compute contribution to the rotated matrices from iproc
488 : ABI_MALLOC(left_temp, (2,npw*nspinor*buffsize_iproc(1)))
489 : ABI_MALLOC(right_temp, (2,npw*nspinor*buffsize_iproc(2)))
490 :
491 : ! cg
492 : call from_mat_to_block_cyclic(cg, npw*nspinor, nband, left_temp, &
493 : & buffsize_iproc(1), blocksize, coords_iproc(1), grid_dims(1))
494 : call abi_xgemm('n','n',vectsize,buffsize_iproc(2),buffsize_iproc(1),cone,left_temp,vectsize,&
495 : & evec_iproc, buffsize_iproc(1), czero, right_temp, vectsize, x_cplx=cplx)
496 : call from_block_cyclic_to_mat(cg_new, npw*nspinor, nband, right_temp, &
497 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
498 :
499 : ! ghc
500 : call from_mat_to_block_cyclic(ghc, npw*nspinor, nband, left_temp, &
501 : & buffsize_iproc(1), blocksize, coords_iproc(1), grid_dims(1))
502 : call abi_xgemm('n','n',vectsize,buffsize_iproc(2),buffsize_iproc(1),cone,left_temp,vectsize,&
503 : & evec_iproc, buffsize_iproc(1), czero, right_temp, vectsize,x_cplx=cplx)
504 : call from_block_cyclic_to_mat(ghc_new, npw*nspinor, nband, right_temp,&
505 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
506 :
507 : ! gsc or vnlc
508 : if(usepaw == 1) then
509 : call from_mat_to_block_cyclic(gsc, npw*nspinor, nband, left_temp, &
510 : & buffsize_iproc(1), blocksize, coords_iproc(1), grid_dims(1))
511 : endif
512 : if(usepaw==0 .or. has_fock)then
513 : call from_mat_to_block_cyclic(gvnlxc, npw*nspinor, nband, left_temp, &
514 : & buffsize_iproc(1), blocksize, coords_iproc(1), grid_dims(1))
515 : end if
516 : call abi_xgemm('n','n',vectsize,buffsize_iproc(2),buffsize_iproc(1),cone,left_temp,vectsize,&
517 : & evec_iproc, buffsize_iproc(1), czero, right_temp, vectsize, x_cplx=cplx)
518 : call from_block_cyclic_to_mat(gsc_or_vnlxc_new, npw*nspinor, nband, right_temp, &
519 : & buffsize_iproc(2), blocksize, coords_iproc(2), grid_dims(2))
520 :
521 : ABI_FREE(evec_iproc)
522 : ABI_FREE(left_temp)
523 : ABI_FREE(right_temp)
524 : end do
525 :
526 : ! Overwrite with _new
527 : cg = cg_new
528 : ghc = ghc_new
529 : if(usepaw == 1) then
530 : gsc = gsc_or_vnlxc_new
531 : endif
532 : if(usepaw==0 .or. has_fock)then
533 : gvnlxc = gsc_or_vnlxc_new
534 : end if
535 : call timab(timer_rotation, 2, tsec)
536 :
537 : call sca_ham%free()
538 : call sca_ovl%free()
539 : call sca_evec%free()
540 :
541 : end subroutine rayleigh_ritz_distributed
542 : !!***
543 :
544 : !!****f* ABINIT/from_mat_to_block_cyclic
545 : !! NAME
546 : !! from_mat_to_block_cyclic
547 : !!
548 : !! FUNCTION
549 : !! Fills block_cyclic_mat with the columns of full_mat owned by iproc, using a 1D block-cyclic distribution
550 : !!
551 : !! INPUTS
552 : !! full_mat(2,vectsize*nband)=full input matrix
553 : !! vectsize=number of rows
554 : !! nband=number of columns of the full matrix
555 : !! buffsize=size of the local part of the matrix
556 : !! blocksize=size of block for the block-cyclic distribution
557 : !! iproc=local processor number
558 : !! nprocs=total number of processors
559 : !!
560 : !! OUTPUT
561 : !! block_cyclic_mat(2,vectsize*buffsize)=local part of full_mat
562 : !!
563 : !! SIDE EFFECTS
564 : !!
565 : !! SOURCE
566 : subroutine from_mat_to_block_cyclic(full_mat, vectsize, nband, block_cyclic_mat, buffsize, blocksize, iproc, nprocs)
567 :
568 : integer, intent(in) :: vectsize, nband, buffsize, blocksize, iproc, nprocs
569 : real(dp), intent(in) :: full_mat(2, vectsize*nband)
570 : real(dp), intent(inout) :: block_cyclic_mat(2, vectsize*buffsize)
571 :
572 : integer :: shift_fullmat, shift_block_cyclic_mat
573 : integer :: cur_bsize
574 :
575 : ! *************************************************************************
576 :
577 : shift_fullmat = iproc*blocksize
578 : shift_block_cyclic_mat = 0
579 :
580 : do while(.true.)
581 : cur_bsize = MIN(blocksize, nband-shift_fullmat)
582 : if(cur_bsize <= 0) exit
583 : block_cyclic_mat(:, shift_block_cyclic_mat*vectsize+1 : shift_block_cyclic_mat*vectsize + cur_bsize*vectsize) = &
584 : & full_mat(:, shift_fullmat*vectsize+1 : shift_fullmat*vectsize + cur_bsize*vectsize)
585 :
586 : shift_block_cyclic_mat = shift_block_cyclic_mat + blocksize
587 : shift_fullmat = shift_fullmat + blocksize*nprocs
588 : end do
589 :
590 : end subroutine from_mat_to_block_cyclic
591 : !!***
592 :
593 : !!****f* ABINIT/from_block_cyclic_to_mat
594 : !! NAME
595 : !! from_block_cyclic_to_mat
596 : !!
597 : !! FUNCTION
598 : !! Fills the columns of full_mat owned by iproc with block_cyclic_mat, using a 1D block-cyclic distribution
599 : !!
600 : !! INPUTS
601 : !! block_cyclic_mat(2,vectsize*buffsize)=local part of full_mat
602 : !! vectsize=number of rows
603 : !! nband=number of columns of the full matrix
604 : !! buffsize=size of the local part of the matrix
605 : !! blocksize=size of block for the block-cyclic distribution
606 : !! iproc=local processor number
607 : !! nprocs=total number of processors
608 : !!
609 : !! OUTPUT
610 : !! full_mat(2,vectsize*nband)=full matrix
611 : !!
612 : !! SIDE EFFECTS
613 : !!
614 : !! SOURCE
615 :
616 : subroutine from_block_cyclic_to_mat(full_mat, vectsize, nband, block_cyclic_mat, buffsize, blocksize, iproc, nprocs)
617 :
618 : integer, intent(in) :: vectsize, nband, buffsize, blocksize, iproc, nprocs
619 : real(dp), intent(inout) :: full_mat(2, vectsize*nband)
620 : real(dp), intent(in) :: block_cyclic_mat(2, vectsize*buffsize)
621 :
622 : integer :: shift_fullmat, shift_block_cyclic_mat
623 : integer :: cur_bsize
624 :
625 : ! *************************************************************************
626 :
627 : shift_fullmat = iproc*blocksize
628 : shift_block_cyclic_mat = 0
629 :
630 : do while(.true.)
631 : cur_bsize = MIN(blocksize, nband-shift_fullmat)
632 : if(cur_bsize <= 0) exit
633 : full_mat(:, shift_fullmat*vectsize+1 : shift_fullmat*vectsize + cur_bsize*vectsize) =&
634 : & full_mat(:, shift_fullmat*vectsize+1 : shift_fullmat*vectsize + cur_bsize*vectsize) +&
635 : & block_cyclic_mat(:, shift_block_cyclic_mat*vectsize+1 : shift_block_cyclic_mat*vectsize + cur_bsize*vectsize)
636 :
637 : shift_block_cyclic_mat = shift_block_cyclic_mat + blocksize
638 : shift_fullmat = shift_fullmat + blocksize*nprocs
639 : end do
640 :
641 : end subroutine from_block_cyclic_to_mat
642 : !!***
643 :
644 : #endif
645 : !ScaLapack
646 :
647 : end module m_rayleigh_ritz
648 : !!***
|