Branch data Line data Source code
1 : : !!****m* ABINIT/m_chebfi
2 : : !! NAME
3 : : !! m_chebfi
4 : : !!
5 : : !! FUNCTION
6 : : !!
7 : : !!
8 : : !! COPYRIGHT
9 : : !! Copyright (C) 2014-2026 ABINIT group (AL)
10 : : !! This file is distributed under the terms of the
11 : : !! GNU General Public License, see ~abinit/COPYING
12 : : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : : !!
14 : : !! SOURCE
15 : :
16 : : #if defined HAVE_CONFIG_H
17 : : #include "config.h"
18 : : #endif
19 : :
20 : : #include "abi_common.h"
21 : :
22 : : module m_chebfi
23 : :
24 : : use defs_basis
25 : : use m_errors
26 : : use m_xmpi
27 : : use m_abicore
28 : : use m_abi_linalg
29 : : use m_rayleigh_ritz
30 : : use m_invovl
31 : : use m_dtset
32 : :
33 : : use defs_abitypes, only : mpi_type
34 : : use m_time, only : timab
35 : : use m_cgtools, only : dotprod_g
36 : : use m_bandfft_kpt, only : bandfft_kpt, bandfft_kpt_get_ikpt
37 : : use m_pawcprj, only : pawcprj_type, pawcprj_alloc, pawcprj_free, pawcprj_axpby, pawcprj_copy
38 : : use m_hamiltonian, only : gs_hamiltonian_type
39 : : use m_getghc, only : getghc
40 : : use m_prep_kgb, only : prep_getghc, prep_index_wavef_bandpp
41 : :
42 : : implicit none
43 : :
44 : : private
45 : : !!***
46 : :
47 : : public :: chebfi
48 : : !!***
49 : :
50 : : contains
51 : : !!***
52 : :
53 : :
54 : : !!****f* ABINIT/chebfi
55 : : !! NAME
56 : : !! chebfi
57 : : !!
58 : : !! FUNCTION
59 : : !! this routine updates the wave functions at a given k-point,
60 : : !! using the ChebFi method (see paper by A. Levitt and M. Torrent)
61 : : !!
62 : : !! INPUTS
63 : : !! dtset <type(dataset_type)>=all input variales for this dataset
64 : : !! gs_hamk <type(gs_hamiltonian_type)>=all data for the hamiltonian at k
65 : : !! kinpw(npw)=(modified) kinetic energy for each plane wave (hartree)
66 : : !! mpi_enreg=information about MPI parallelization
67 : : !! nband=number of bands at this k point for that spin polarization
68 : : !! npw=number of plane waves at this k point
69 : : !! nspinor=number of plane waves at this k point
70 : : !! prtvol=control print volume and debugging output
71 : : !!
72 : : !! OUTPUT
73 : : !! eig(nband)=array for holding eigenvalues (hartree)
74 : : !! resid(nband)=residuals for each states
75 : : !! If gs_hamk%usepaw==1:
76 : : !! gsc(2,*)=<g|s|c> matrix elements (s=overlap)
77 : : !! If gs_hamk%usepaw==0
78 : : !! enlx(nband)=contribution from each band to nonlocal psp + potential Fock ACE part of total energy, at this k-point
79 : : !!
80 : : !! SIDE EFFECTS
81 : : !! cg(2,*)=updated wavefunctions
82 : : !!
83 : : !! NOTES
84 : : !! -- TODO --
85 : : !! Normev?
86 : : !! Ecutsm
87 : : !! nspinor 2
88 : : !! spinors parallelisation
89 : : !! fock
90 : : !! -- Performance --
91 : : !! Improve load balancing
92 : : !! Don't diagonalize converged eigenvectors, just orthogonalize
93 : : !! Maybe don't diagonalize so often (once every two outer iterations?)
94 : : !! Benchmark diagonalizations, choose np_slk
95 : : !! How to chose npfft?
96 : : !! Implement MINRES for invovl
97 : : !! -- LOBPCG --
98 : : !! Improve stability (see paper by Lehoucq Sorensen, maybe use bunch-kaufman factorizations?)
99 : : !!
100 : : !! SOURCE
101 : :
102 : 48 : subroutine chebfi(cg,dtset,eig,enlx,gs_hamk,gsc,kinpw,mpi_enreg,nband,npw,nspinor,prtvol,resid)
103 : :
104 : : !Arguments ------------------------------------
105 : : type(gs_hamiltonian_type),intent(inout) :: gs_hamk
106 : : type(dataset_type),intent(in) :: dtset
107 : : type(mpi_type),intent(inout) :: mpi_enreg
108 : : integer,intent(in) :: nband,npw,prtvol,nspinor
109 : : real(dp),intent(inout), target :: cg(2,npw*nspinor*nband),gsc(2,npw*nspinor*nband)
110 : : real(dp),intent(in) :: kinpw(npw)
111 : : real(dp),intent(out) :: resid(nband)
112 : : real(dp),intent(out) :: enlx(nband)
113 : : real(dp),intent(out) :: eig(nband)
114 : :
115 : : !Local variables-------------------------------
116 : 96 : real(dp) :: pcon(npw)
117 : : real(dp) :: filter_low
118 : : real(dp) :: filter_center, filter_radius
119 : 144 : real(dp), dimension(2, npw*nspinor*nband), target :: ghc, gvnlxc
120 : 48 : real(dp), allocatable, dimension(:,:) :: cg_filter_next, cg_filter_prev, gsm1hc_filter, gsc_filter_prev, gsc_filter_next
121 : 48 : real(dp), allocatable, dimension(:,:), target :: cg_alltoall1,gsc_alltoall1,ghc_alltoall1,gvnlxc_alltoall1
122 : 48 : real(dp), allocatable, dimension(:,:), target :: cg_alltoall2,gsc_alltoall2,ghc_alltoall2,gvnlxc_alltoall2
123 : 48 : real(dp), pointer, dimension(:,:) :: cg_filter, gsc_filter, ghc_filter, gvnlxc_filter
124 : 96 : real(dp) :: resid_vec(2, npw*nspinor)
125 : : logical :: has_fock,paw
126 : : integer :: shift, shift_cg_loadbalanced
127 : : integer :: iband, ideg, ispinor
128 : : integer :: sij_opt, cpopt
129 : : real(dp) :: eval, tsec(2)
130 : : integer :: tim_getghc = 5, ierr
131 : : integer :: i
132 : 48 : integer, allocatable :: index_wavef_band(:)
133 : : real(dp) :: maxeig, mineig
134 : 48 : real(dp), allocatable :: resids_filter(:), residvec_filter(:,:)
135 : 48 : integer, allocatable :: ndeg_filter_bands(:)
136 : : integer :: iactive, nactive
137 : : real(dp) :: ampfactor
138 : : integer :: ndeg_filter_max, ndeg_filter_decrease, ndeg_filter_tolwfr
139 : : ! real(dp) :: load_imbalance
140 : : integer :: mcg
141 : : real(dp) :: dprod_r, dprod_i
142 : : character(len=500) :: message
143 : 96 : integer :: rdisplsloc(mpi_enreg%nproc_band), recvcountsloc(mpi_enreg%nproc_band)
144 : 96 : integer :: sdisplsloc(mpi_enreg%nproc_band), sendcountsloc(mpi_enreg%nproc_band)
145 : : integer :: ikpt_this_proc, npw_filter, nband_filter
146 : 48 : type(pawcprj_type), allocatable :: cwaveprj(:,:), cwaveprj_next(:,:), cwaveprj_prev(:,:)
147 : : ! integer :: ndeg_filter_total
148 : :
149 : : ! timers
150 : : integer, parameter :: timer_chebfi = 1600, timer_alltoall = 1601, timer_apply_inv_ovl = 1602, timer_rotation = 1603
151 : : integer, parameter :: timer_subdiago = 1604, timer_subham = 1605, timer_ortho = 1606, timer_getghc = 1607
152 : : integer, parameter :: timer_residuals = 1608, timer_update_eigen = 1609, timer_sync = 1610
153 : :
154 : : ! *************************************************************************
155 : :
156 : : !======================================================================================================
157 : : ! Initialize, transpose input cg if paral_kgb
158 : : !======================================================================================================
159 : 48 : call timab(timer_chebfi,1,tsec)
160 : :
161 : : !Initializations
162 : 48 : paw = gs_hamk%usepaw == 1
163 : 48 : has_fock=(associated(gs_hamk%fockcommon))
164 : 48 : mcg = npw*nspinor*nband
165 : :
166 : : ! Init pcon
167 [ + + ]: 3156 : pcon = (27+kinpw*(18+kinpw*(12+8*kinpw))) / (27+kinpw*(18+kinpw*(12+8*kinpw)) + 16*kinpw**4)
168 : :
169 [ + + + + : 223824 : ghc=zero; gvnlxc=zero
+ + + + ]
170 : :
171 : : ! Initialize the _filter pointers. Depending on paral_kgb, they might point to the actual arrays or to _alltoall variables
172 [ + - ]: 48 : if (dtset%paral_kgb == 1) then
173 : 48 : ikpt_this_proc = bandfft_kpt_get_ikpt()
174 : 48 : npw_filter = bandfft_kpt(ikpt_this_proc)%ndatarecv
175 : 48 : nband_filter = mpi_enreg%bandpp
176 : :
177 [ - + + - : 144 : ABI_MALLOC(cg_alltoall1, (2, npw_filter*nspinor*nband_filter))
+ - + - -
+ - + ]
178 [ - + + - : 96 : ABI_MALLOC(gsc_alltoall1, (2, npw_filter*nspinor*nband_filter))
- + - + ]
179 [ - + + - : 96 : ABI_MALLOC(ghc_alltoall1, (2, npw_filter*nspinor*nband_filter))
- + - + ]
180 [ - + + - : 96 : ABI_MALLOC(gvnlxc_alltoall1, (2, npw_filter*nspinor*nband_filter))
- + - + ]
181 [ - + + - : 96 : ABI_MALLOC(cg_alltoall2, (2, npw_filter*nspinor*nband_filter))
- + - + ]
182 [ - + + - : 96 : ABI_MALLOC(gsc_alltoall2, (2, npw_filter*nspinor*nband_filter))
- + - + ]
183 [ - + + - : 96 : ABI_MALLOC(ghc_alltoall2, (2, npw_filter*nspinor*nband_filter))
- + - + ]
184 [ - + + - : 96 : ABI_MALLOC(gvnlxc_alltoall2, (2, npw_filter*nspinor*nband_filter))
- + - + ]
185 : :
186 : : ! Init tranpose variables
187 [ + + ]: 144 : recvcountsloc = bandfft_kpt(ikpt_this_proc)%recvcounts * 2 * nspinor * mpi_enreg%bandpp
188 [ + + ]: 144 : rdisplsloc = bandfft_kpt(ikpt_this_proc)%rdispls * 2 * nspinor * mpi_enreg%bandpp
189 [ + + ]: 144 : sendcountsloc = bandfft_kpt(ikpt_this_proc)%sendcounts * 2 * nspinor
190 [ + + ]: 144 : sdisplsloc = bandfft_kpt(ikpt_this_proc)%sdispls * 2 * nspinor
191 : :
192 : : ! Load balancing, so that each processor has approximately the same number of converged and non-converged bands
193 : : ! for two procs, rearrange 1 2 3 4 5 6 as 1 4 2 5 3 6
194 : : !
195 : : ! trick to save memory: ghc has the necessary size, and will be overwritten afterwards anyway
196 : : #define cg_loadbalanced ghc
197 : 48 : shift = 0
198 [ + + ]: 144 : do i=1, mpi_enreg%nproc_band
199 [ + + ]: 720 : do iband=1, mpi_enreg%bandpp
200 : 576 : shift_cg_loadbalanced = (i-1 + (iband-1)*mpi_enreg%nproc_band)*npw*nspinor
201 [ + + + + ]: 112464 : cg_loadbalanced(:, shift+1:shift+npw*nspinor) = cg(:, shift_cg_loadbalanced+1:shift_cg_loadbalanced+npw*nspinor)
202 : 672 : shift = shift + npw*nspinor
203 : : end do
204 : : end do
205 : :
206 : : ! Transpose input cg into cg_alloall1. cg_alltoall1 is now (npw_filter, nband_filter)
207 : 48 : call timab(timer_alltoall, 1, tsec)
208 : : call xmpi_alltoallv(cg_loadbalanced,sendcountsloc,sdisplsloc,cg_alltoall1,&
209 : 48 : & recvcountsloc,rdisplsloc,mpi_enreg%comm_band,ierr)
210 : 48 : call timab(timer_alltoall, 2, tsec)
211 : : #undef cg_loadbalanced
212 : :
213 : : ! sort according to bandpp (from lobpcg, I don't fully understand what's going on but it works and it's fast)
214 : : call prep_index_wavef_bandpp(mpi_enreg%nproc_band,mpi_enreg%bandpp,&
215 : : & nspinor,bandfft_kpt(ikpt_this_proc)%ndatarecv,&
216 : : & bandfft_kpt(ikpt_this_proc)%recvcounts,bandfft_kpt(ikpt_this_proc)%rdispls,&
217 : 48 : & index_wavef_band)
218 : :
219 [ + + + + ]: 111936 : cg_alltoall2(:,:) = cg_alltoall1(:,index_wavef_band)
220 : :
221 : 48 : cg_filter => cg_alltoall2
222 : 48 : gsc_filter => gsc_alltoall2
223 : 48 : ghc_filter => ghc_alltoall2
224 : 48 : gvnlxc_filter => gvnlxc_alltoall2
225 : : else
226 : 0 : npw_filter = npw
227 : 0 : nband_filter = nband
228 : :
229 : 0 : cg_filter => cg
230 : 0 : gsc_filter => gsc
231 : 0 : ghc_filter => ghc
232 : 0 : gvnlxc_filter => gvnlxc
233 : : end if
234 : : ! from here to the next alltoall, all computation is done on _filter variables, agnostic
235 : : ! to whether it's nband x npw (paral_kgb == 0) or ndatarecv*bandpp (paral_kgb = 1)
236 : :
237 : : ! Allocate filter variables for the application of the Chebyshev polynomial
238 [ - + + - : 144 : ABI_MALLOC(cg_filter_next, (2, npw_filter*nspinor*nband_filter))
+ - + - -
+ - + ]
239 [ - + + - : 96 : ABI_MALLOC(cg_filter_prev, (2, npw_filter*nspinor*nband_filter))
- + - + ]
240 [ - + + - : 96 : ABI_MALLOC(gsc_filter_prev, (2, npw_filter*nspinor*nband_filter))
- + - + ]
241 [ - + + - : 96 : ABI_MALLOC(gsc_filter_next, (2, npw_filter*nspinor*nband_filter))
- + - + ]
242 [ - + + - : 96 : ABI_MALLOC(gsm1hc_filter, (2, npw_filter*nspinor*nband_filter))
- + - + ]
243 : :
244 : : ! PAW init
245 [ + - ]: 48 : if(paw) then
246 [ - + + - : 1056 : ABI_MALLOC(cwaveprj, (gs_hamk%natom,nspinor*nband_filter))
- + + - +
- + - - +
- + - + +
+ + + +
- ]
247 [ - + + - : 1056 : ABI_MALLOC(cwaveprj_next, (gs_hamk%natom,nspinor*nband_filter))
- + + - +
- + - - +
- + + + +
+ ]
248 [ - + + - : 1056 : ABI_MALLOC(cwaveprj_prev, (gs_hamk%natom,nspinor*nband_filter))
- + + - +
- + - - +
- + + + +
+ ]
249 : 48 : call pawcprj_alloc(cwaveprj,0,gs_hamk%dimcprj)
250 : 48 : call pawcprj_alloc(cwaveprj_next,0,gs_hamk%dimcprj)
251 : 48 : call pawcprj_alloc(cwaveprj_prev,0,gs_hamk%dimcprj)
252 : :
253 : 48 : sij_opt = 1 ! recompute S
254 : 48 : cpopt = 0 ! save cprojs
255 : : else
256 : 0 : sij_opt = 0
257 : 0 : cpopt = -1
258 : : end if
259 : :
260 : :
261 : :
262 : : !======================================================================================================
263 : : ! Data in npfft x npband distribution. First getghc, update eigenvalues and residuals
264 : : !======================================================================================================
265 : 48 : write(message, *) 'First getghc'
266 : 48 : call wrtout(std_out,message,'COLL')
267 : :
268 : : ! get_ghc on cg
269 : 48 : call timab(timer_getghc, 1, tsec)
270 [ - + ]: 48 : if (dtset%paral_kgb == 0) then
271 : : call getghc(cpopt,cg_filter,cwaveprj,ghc_filter,gsc_filter,gs_hamk,gvnlxc_filter,&
272 : 0 : & eval,mpi_enreg,nband,prtvol,sij_opt,tim_getghc,0)
273 : : else
274 : : call prep_getghc(cg_filter,gs_hamk,gvnlxc_filter,ghc_filter,gsc_filter,eval,nband,mpi_enreg,&
275 : 48 : & prtvol,sij_opt,cpopt,cwaveprj,already_transposed=.true.)
276 : : end if
277 : 48 : call timab(timer_getghc, 2, tsec)
278 : :
279 : : ! Debug barrier: should be invisible
280 : 48 : call timab(timer_sync, 1, tsec)
281 : 48 : call xmpi_barrier(mpi_enreg%comm_band)
282 : 48 : call timab(timer_sync, 2, tsec)
283 : :
284 : 48 : write(message, *) 'Computing residuals'
285 : 48 : call wrtout(std_out,message,'COLL')
286 : : ! update eigenvalues and residuals
287 : 48 : call timab(timer_update_eigen, 1, tsec)
288 [ - + + - : 144 : ABI_MALLOC(resids_filter, (nband_filter))
+ - + - -
+ - + ]
289 [ - + + - : 144 : ABI_MALLOC(residvec_filter, (2, npw_filter*nspinor))
+ - + - -
+ - + ]
290 [ - + + - : 144 : ABI_MALLOC(ndeg_filter_bands, (nband_filter))
+ - + - -
+ - + ]
291 [ + + ]: 336 : do iband=1, nband_filter
292 : 288 : shift = npw_filter*nspinor*(iband-1)
293 : : call dotprod_g(eig(iband),dprod_i,gs_hamk%istwf_k,npw_filter*nspinor,1,ghc_filter(:, shift+1:shift+npw_filter*nspinor),&
294 [ - + - + ]: 288 : & cg_filter(:, shift+1:shift+npw_filter*nspinor),mpi_enreg%me_g0,mpi_enreg%comm_spinorfft)
295 [ - + ]: 288 : if(paw) then
296 : : call dotprod_g(dprod_r,dprod_i,gs_hamk%istwf_k,npw_filter*nspinor,1,gsc_filter(:, shift+1:shift+npw_filter*nspinor),&
297 [ - + - + ]: 288 : & cg_filter(:, shift+1:shift+npw_filter*nspinor),mpi_enreg%me_g0,mpi_enreg%comm_spinorfft)
298 : 288 : eig(iband) = eig(iband)/dprod_r
299 : : end if
300 : :
301 : : if(paw) then
302 : : residvec_filter = ghc_filter(:, shift+1 : shift+npw_filter*nspinor) &
303 [ + - - + : 112464 : & - eig(iband)*gsc_filter(:, shift+1 : shift+npw_filter*nspinor)
- - + + +
+ ]
304 : : else
305 : : residvec_filter = ghc_filter(:, shift+1 : shift+npw_filter*nspinor) &
306 [ # # # # : 0 : & - eig(iband)*cg_filter(:, shift+1 : shift+npw_filter*nspinor)
# # # # #
# ]
307 : : end if
308 [ + + + + ]: 112224 : resids_filter(iband) = SUM(residvec_filter**2)
309 : : end do
310 : 48 : call xmpi_sum(resids_filter,mpi_enreg%comm_fft,ierr)
311 [ + - - + : 384 : call xmpi_max(MAXVAL(eig(1:nband_filter)),maxeig,mpi_enreg%comm_band,ierr)
- - + + ]
312 [ + - - + : 384 : call xmpi_min(MINVAL(eig(1:nband_filter)),mineig,mpi_enreg%comm_band,ierr)
- - + + ]
313 : 48 : filter_low = maxeig
314 : 48 : call timab(timer_update_eigen, 2, tsec)
315 : :
316 : : ! Decide which polynomial filter degree per band is needed
317 : : ! don't go above this, or face bad conditioning of the Gram matrix.
318 : 48 : ndeg_filter_max = cheb_oracle(mineig, filter_low, dtset%ecut, 1e-16_dp, 40)
319 [ + + ]: 336 : do iband=1, nband_filter
320 : : ! Filter degree necessary to converge to tolwfr
321 : 288 : ndeg_filter_tolwfr = cheb_oracle(eig(iband), filter_low, dtset%ecut, dtset%tolwfr_diago / resids_filter(iband), dtset%mdeg_filter)
322 : : ! Filter degree necessary to decrease residual by a constant factor
323 : : ndeg_filter_decrease = cheb_oracle(eig(iband), filter_low, dtset%ecut, 0.1_dp, dtset%mdeg_filter)
324 : :
325 : 288 : ndeg_filter_bands(iband) = MAX(MIN(ndeg_filter_tolwfr, ndeg_filter_decrease, ndeg_filter_max, dtset%mdeg_filter), 1)
326 : 336 : ndeg_filter_bands(iband) = dtset%mdeg_filter ! fiddle with this to use locking
327 : : end do
328 : :
329 : :
330 : : !!!!! Uncomment for diagnostics
331 : : ! ndeg_filter_total = SUM(ndeg_filter_bands)
332 : : ! call xmpi_sum(ndeg_filter_total, mpi_enreg%comm_band, ierr)
333 : : ! load_imbalance = (SUM(ndeg_filter_bands) - REAL(ndeg_filter_total)/REAL(mpi_enreg%nproc_band)) / &
334 : : ! & (REAL(ndeg_filter_total)/REAL(mpi_enreg%nproc_band))
335 : : ! call xmax_mpi(load_imbalance, mpi_enreg%comm_band, ierr)
336 : :
337 : : ! write(message, *) 'Mean ndeg_filter', REAL(ndeg_filter_total)/REAL(nband), 'max imbalance (%)', load_imbalance*100
338 : : ! call wrtout(std_out,message,'COLL')
339 : :
340 [ - + ]: 48 : ABI_FREE(resids_filter)
341 [ - + ]: 48 : ABI_FREE(residvec_filter)
342 : :
343 : : !======================================================================================================
344 : : ! Chebyshev polynomial application
345 : : !======================================================================================================
346 : : ! Filter by a chebyshev polynomial of max. degree mdeg_filter
347 [ + + ]: 336 : do ideg=1,dtset%mdeg_filter
348 : : ! Filter only on [iactive, iactive+nactive-1]
349 : 288 : iactive = nband_filter
350 [ + - ]: 288 : do iband = 1, nband_filter
351 : : ! does iband need a higher degree for polynomila filter?
352 [ - + ]: 288 : if (ndeg_filter_bands(iband) >= ideg) then
353 : : iactive = iband
354 : : exit
355 : : end if
356 : : end do
357 : 288 : nactive = nband_filter - iactive + 1
358 : 288 : shift = npw_filter*nspinor*(iactive-1) + 1
359 : : ! trick the legacy prep_getghc
360 : 288 : mpi_enreg%bandpp = nactive
361 : :
362 : : ! Define the filter position
363 : 288 : filter_center = (dtset%ecut+filter_low)/2
364 : 288 : filter_radius = (dtset%ecut-filter_low)/2
365 : :
366 : : ! write(message, *) 'Applying invovl, iteration', ideg
367 : : ! call wrtout(std_out,message,'COLL')
368 : :
369 : : ! If paw, have to apply S^-1
370 [ + - ]: 288 : if(paw) then
371 : 288 : call timab(timer_apply_inv_ovl, 1, tsec)
372 : : call apply_invovl(gs_hamk, ghc_filter(:,shift:), gsm1hc_filter(:,shift:), cwaveprj_next(:,iactive:), &
373 [ - + ]: 288 : & npw_filter, nactive, mpi_enreg, nspinor, dtset%invovl_blksliced, dtset%invovl_precision)
374 : 288 : call timab(timer_apply_inv_ovl, 2, tsec)
375 : : else
376 [ # # # # ]: 0 : gsm1hc_filter(:,shift:) = ghc_filter(:,shift:)
377 : : end if
378 : :
379 : : ! Chebyshev iteration: UPDATE cg
380 [ + + ]: 288 : if(ideg == 1) then
381 [ + + + + ]: 111936 : cg_filter_next(:,shift:) = one/filter_radius * (gsm1hc_filter(:,shift:) - filter_center*cg_filter(:,shift:))
382 : : else
383 : : cg_filter_next(:,shift:) = two/filter_radius * (gsm1hc_filter(:,shift:) - filter_center*cg_filter(:,shift:)) &
384 [ + + + + ]: 559680 : & - cg_filter_prev(:,shift:)
385 : : end if
386 : : ! Update gsc and cwaveprj
387 [ + - ]: 288 : if(paw) then
388 [ + + ]: 288 : if(ideg == 1) then
389 [ + + + + ]: 111936 : gsc_filter_next(:,shift:) = one/filter_radius * (ghc_filter(:,shift:) - filter_center*gsc_filter(:,shift:))
390 : : !cwaveprj_next = one/filter_radius * (cwaveprj_next - filter_center*cwaveprj)
391 : 48 : call pawcprj_axpby(-filter_center/filter_radius, one/filter_radius,cwaveprj(:,iactive:),cwaveprj_next(:,iactive:))
392 : : else
393 : : gsc_filter_next(:,shift:) = two/filter_radius * (ghc_filter(:,shift:) - filter_center*gsc_filter(:,shift:))&
394 [ + + + + ]: 559680 : & - gsc_filter_prev(:,shift:)
395 : : !cwaveprj_next = two/filter_radius * (cwaveprj_next - filter_center*cwaveprj) - cwaveprj_prev
396 : 240 : call pawcprj_axpby(-two*filter_center/filter_radius, two/filter_radius,cwaveprj(:,iactive:),cwaveprj_next(:,iactive:))
397 : 240 : call pawcprj_axpby(-one, one,cwaveprj_prev(:,iactive:),cwaveprj_next(:,iactive:))
398 : : end if
399 : : end if
400 : :
401 : : ! Bookkeeping of the _prev variables
402 [ + + + + ]: 671616 : cg_filter_prev(:,shift:) = cg_filter(:,shift:)
403 [ + + + + ]: 671616 : cg_filter(:,shift:) = cg_filter_next(:,shift:)
404 [ - + ]: 288 : if(paw) then
405 [ + + + + ]: 671616 : gsc_filter_prev(:,shift:) = gsc_filter(:,shift:)
406 [ + + + + ]: 671616 : gsc_filter(:,shift:) = gsc_filter_next(:,shift:)
407 : :
408 : 288 : call pawcprj_copy(cwaveprj(:,iactive:),cwaveprj_prev(:,iactive:))
409 : 288 : call pawcprj_copy(cwaveprj_next(:,iactive:),cwaveprj(:,iactive:))
410 : : end if
411 : :
412 : : ! Update ghc
413 : : if(paw) then
414 : : !! DEBUG use this to remove the optimization and recompute gsc/cprojs
415 : : ! sij_opt = 1
416 : : ! cpopt = 0
417 : :
418 : 288 : sij_opt = 0 ! gsc is already computed
419 : 288 : cpopt = 2 ! reuse cprojs
420 : : else
421 : 0 : sij_opt = 0
422 : 0 : cpopt = -1
423 : : end if
424 : :
425 : 288 : write(message, *) 'Getghc, degree of polynom', ideg
426 : 288 : call wrtout(std_out,message,'COLL')
427 : :
428 : 288 : call timab(timer_getghc, 1, tsec)
429 [ - + ]: 288 : if (dtset%paral_kgb == 0) then
430 : : call getghc(cpopt,cg_filter(:,shift:),cwaveprj(:,iactive:),ghc_filter(:,shift:),&
431 : : & gsc_filter(:,shift:),gs_hamk,gvnlxc_filter(:,shift:),eval,mpi_enreg,&
432 : 0 : & nband,prtvol,sij_opt,tim_getghc,0)
433 : : else
434 : : call prep_getghc(cg_filter(:,shift:),gs_hamk,gvnlxc_filter(:,shift:),ghc_filter(:,shift:),&
435 : : & gsc_filter(:,shift:),eval,nband,mpi_enreg,prtvol,sij_opt,cpopt,&
436 : 288 : & cwaveprj(:,iactive:),already_transposed=.true.)
437 : : end if
438 : :
439 : : ! end of the trick
440 : 288 : mpi_enreg%bandpp = nband_filter
441 : :
442 : 336 : call timab(timer_getghc, 2, tsec)
443 : : end do ! end loop on ideg
444 : :
445 : : ! normalize according to the previously computed rayleigh quotients (inaccurate, but cheap)
446 [ + + ]: 336 : do iband = 1, nband_filter
447 : 288 : ampfactor = cheb_poly(eig(iband), ndeg_filter_bands(iband), filter_low, dtset%ecut)
448 [ - + ]: 288 : if(abs(ampfactor) < 1e-3) ampfactor = 1e-3 ! just in case, avoid amplifying too much
449 : 288 : shift = npw_filter*nspinor*(iband-1)
450 [ + + + + ]: 112176 : cg_filter(:, shift+1:shift+npw_filter*nspinor) = cg_filter(:, shift+1:shift+npw_filter*nspinor) / ampfactor
451 [ + + + + ]: 112176 : ghc_filter(:, shift+1:shift+npw_filter*nspinor) = ghc_filter(:, shift+1:shift+npw_filter*nspinor) / ampfactor
452 [ + - ]: 288 : if(paw) then
453 [ + + + + ]: 112176 : gsc_filter(:, shift+1:shift+npw_filter*nspinor) = gsc_filter(:, shift+1:shift+npw_filter*nspinor) / ampfactor
454 : : endif
455 [ - + ]: 336 : if(.not.paw .or. has_fock)then
456 [ # # # # ]: 0 : gvnlxc_filter(:, shift+1:shift+npw_filter*nspinor) = gvnlxc_filter(:, shift+1:shift+npw_filter*nspinor) / ampfactor
457 : : end if
458 : : end do
459 : :
460 : : ! Cleanup
461 [ + - ]: 48 : if(paw) then
462 : 48 : call pawcprj_free(cwaveprj)
463 : 48 : call pawcprj_free(cwaveprj_next)
464 : 48 : call pawcprj_free(cwaveprj_prev)
465 [ + - + + : 624 : ABI_FREE(cwaveprj)
- + - + -
+ ]
466 [ + - + + : 624 : ABI_FREE(cwaveprj_next)
- + - + -
+ ]
467 [ + - + + : 624 : ABI_FREE(cwaveprj_prev)
- + - + -
+ ]
468 : : end if
469 [ - + ]: 48 : ABI_FREE(ndeg_filter_bands)
470 [ - + ]: 48 : ABI_FREE(cg_filter_next)
471 [ - + ]: 48 : ABI_FREE(cg_filter_prev)
472 [ - + ]: 48 : ABI_FREE(gsc_filter_prev)
473 [ - + ]: 48 : ABI_FREE(gsc_filter_next)
474 [ - + ]: 48 : ABI_FREE(gsm1hc_filter)
475 : :
476 : : !======================================================================================================
477 : : ! Filtering done, tranpose back
478 : : !======================================================================================================
479 : :
480 : 48 : write(message, *) 'Filtering done, transposing back'
481 : 48 : call wrtout(std_out,message,'COLL')
482 : :
483 : : ! transpose back
484 [ - + ]: 48 : if(dtset%paral_kgb == 1) then
485 [ + + + + ]: 111936 : cg_alltoall1(:,index_wavef_band) = cg_alltoall2(:,:)
486 [ + + + + ]: 111936 : ghc_alltoall1(:,index_wavef_band) = ghc_alltoall2(:,:)
487 [ + - ]: 48 : if(paw) then
488 [ + + + + ]: 111936 : gsc_alltoall1(:,index_wavef_band) = gsc_alltoall2(:,:)
489 : : else
490 [ # # # # ]: 0 : gvnlxc_alltoall1(:,index_wavef_band) = gvnlxc_alltoall2(:,:)
491 : : end if
492 : :
493 [ - + ]: 48 : ABI_FREE(index_wavef_band)
494 : :
495 : 48 : call timab(timer_sync, 1, tsec)
496 : 48 : call xmpi_barrier(mpi_enreg%comm_band)
497 : 48 : call timab(timer_sync, 2, tsec)
498 : :
499 : 48 : call timab(timer_alltoall, 1, tsec)
500 : :
501 : : ! Do we pack the arrays in the alltoall, saving latency, or do we do it separately, saving memory and copies?
502 : : call xmpi_alltoallv(cg_alltoall1,recvcountsloc,rdisplsloc,cg,&
503 : 48 : & sendcountsloc,sdisplsloc,mpi_enreg%comm_band,ierr)
504 : : call xmpi_alltoallv(ghc_alltoall1,recvcountsloc,rdisplsloc,ghc,&
505 : 48 : & sendcountsloc,sdisplsloc,mpi_enreg%comm_band,ierr)
506 [ + - ]: 48 : if(paw) then
507 : : call xmpi_alltoallv(gsc_alltoall1,recvcountsloc,rdisplsloc,gsc,&
508 : 48 : & sendcountsloc,sdisplsloc,mpi_enreg%comm_band,ierr)
509 : : else
510 : : call xmpi_alltoallv(gvnlxc_alltoall1,recvcountsloc,rdisplsloc,gvnlxc,&
511 : 0 : & sendcountsloc,sdisplsloc,mpi_enreg%comm_band,ierr)
512 : : end if
513 : 48 : call timab(timer_alltoall, 2, tsec)
514 : :
515 [ - + ]: 48 : if(mpi_enreg%paral_kgb == 1) then
516 [ - + ]: 48 : ABI_FREE(cg_alltoall1)
517 [ - + ]: 48 : ABI_FREE(gsc_alltoall1)
518 [ - + ]: 48 : ABI_FREE(ghc_alltoall1)
519 [ - + ]: 48 : ABI_FREE(gvnlxc_alltoall1)
520 [ - + ]: 48 : ABI_FREE(cg_alltoall2)
521 [ - + ]: 48 : ABI_FREE(gsc_alltoall2)
522 [ - + ]: 48 : ABI_FREE(ghc_alltoall2)
523 [ - + ]: 48 : ABI_FREE(gvnlxc_alltoall2)
524 : : end if
525 : : else
526 : : ! nothing to do, the _filter variables already point to the right ones
527 : : end if
528 : :
529 : :
530 : :
531 : : !======================================================================================================
532 : : ! Data in (npfft*npband) x 1 distribution. Rayleigh-Ritz step
533 : : !======================================================================================================
534 : :
535 : : ! _subdiago might use less memory when using only one proc, should maybe call it, or just remove it
536 : : ! and always call _distributed
537 : : #if defined HAVE_LINALG_SCALAPACK
538 : : call rayleigh_ritz_distributed(cg,ghc,gsc,gvnlxc,eig,has_fock,gs_hamk%istwf_k,mpi_enreg,nband,npw,nspinor,gs_hamk%usepaw)
539 : : #else
540 : 48 : call rayleigh_ritz_subdiago(cg,ghc,gsc,gvnlxc,eig,has_fock,gs_hamk%istwf_k,mpi_enreg,nband,npw,nspinor,gs_hamk%usepaw)
541 : : #endif
542 : :
543 : : ! Build residuals
544 : 48 : call timab(timer_residuals, 1, tsec)
545 [ + + ]: 624 : do iband=1,nband
546 : 576 : shift = npw*nspinor*(iband-1)
547 [ + - ]: 576 : if(paw) then
548 [ + + + + ]: 112464 : resid_vec = ghc(:, shift+1 : shift+npw*nspinor) - eig(iband)*gsc(:, shift+1 : shift+npw*nspinor)
549 : : else
550 [ # # # # ]: 0 : resid_vec = ghc(:, shift+1 : shift+npw*nspinor) - eig(iband)*cg (:, shift+1 : shift+npw*nspinor)
551 : : end if
552 : :
553 : : ! precondition resid_vec
554 [ + + ]: 1152 : do ispinor = 1,nspinor
555 [ + + ]: 37872 : resid_vec(1, npw*(ispinor-1)+1:npw*ispinor) = resid_vec(1, npw*(ispinor-1)+1:npw*ispinor) * pcon
556 [ + + ]: 38448 : resid_vec(2, npw*(ispinor-1)+1:npw*ispinor) = resid_vec(2, npw*(ispinor-1)+1:npw*ispinor) * pcon
557 : : end do
558 : :
559 : : call dotprod_g(resid(iband),dprod_i,gs_hamk%istwf_k,npw*nspinor,1,resid_vec,&
560 : 576 : & resid_vec,mpi_enreg%me_g0,mpi_enreg%comm_bandspinorfft)
561 : :
562 [ + - - + ]: 624 : if(.not. paw .or. has_fock) then
563 : : call dotprod_g(enlx(iband),dprod_i,gs_hamk%istwf_k,npw*nspinor,1,cg(:, shift+1:shift+npw*nspinor),&
564 : 0 : & gvnlxc(:, shift+1:shift+npw_filter*nspinor),mpi_enreg%me_g0,mpi_enreg%comm_bandspinorfft)
565 : : end if
566 : : end do
567 : 48 : call timab(timer_residuals, 2, tsec)
568 : :
569 : : ! write(message, '(a,4e10.2)') 'Resids (1, N, min, max) ', resid(1), resid(nband), MINVAL(resid), MAXVAL(resid)
570 : : ! call wrtout(std_out,message,'COLL')
571 : :
572 : : ! write(message,*)'Eigens(1,nocc,nband) ',eig(1), eig(ilastocc),eig(nband)
573 : : ! call wrtout(std_out,message,'COLL')
574 : : ! write(message,*)'Resids(1,nocc,nband) ',resid(1), resid(ilastocc),resid(nband)
575 : : ! call wrtout(std_out,message,'COLL')
576 : :
577 : 48 : call timab(timer_chebfi,2,tsec)
578 : :
579 [ - + - + : 144 : end subroutine chebfi
- + - + -
+ - + - +
- + - - -
- - - - +
- - - - -
- - + - -
- - - - -
+ - + ]
580 : : !!***
581 : :
582 : : !!****f* ABINIT/cheb_poly
583 : : !! NAME
584 : : !! cheb_poly
585 : : !!
586 : : !! FUNCTION
587 : : !! Computes the value of the Chebyshev polynomial of degree n on the interval [a,b] at x
588 : : !!
589 : : !! INPUTS
590 : : !! x= input variable
591 : : !! n= degree
592 : : !! a= left bound of the interval
593 : : !! b= right bound of the interval
594 : : !!
595 : : !! OUTPUT
596 : : !! y= Tn(x)
597 : : !!
598 : : !! NOTES
599 : : !!
600 : : !! SOURCE
601 : :
602 : 288 : function cheb_poly(x, n, a, b) result(y)
603 : :
604 : : integer, intent(in) :: n
605 : : integer :: i
606 : : real(dp), intent(in) :: x, a, b
607 : : real(dp) :: y, xred, temp
608 : : real(dp) :: yim1
609 : :
610 : : ! *************************************************************************
611 : :
612 : 288 : xred = (x-(a+b)/2)/(b-a)*2
613 : 288 : y = xred
614 : 288 : yim1 = one
615 [ + + ]: 1728 : do i=2, n
616 : 1440 : temp = y
617 : 1440 : y = 2*xred*y - yim1
618 : 1728 : yim1 = temp
619 : : end do
620 : :
621 : 288 : end function cheb_poly
622 : : !!***
623 : :
624 : : !!****f* ABINIT/cheb_oracle
625 : : !! NAME
626 : : !! cheb_oracle
627 : : !!
628 : : !! FUNCTION
629 : : !! Returns the number of necessary iterations to decrease residual by at least tol
630 : : !! Here as in the rest of the code, the convention is that residuals are squared (||Ax-lx||^2)
631 : : !!
632 : : !! INPUTS
633 : : !! x= input variable
634 : : !! a= left bound of the interval
635 : : !! b= right bound of the interval
636 : : !! tol= needed precision
637 : : !! nmax= max number of iterations
638 : : !!
639 : : !! OUTPUT
640 : : !! n= number of iterations needed to decrease residual by tol
641 : : !!
642 : : !! NOTES
643 : : !!
644 : : !! SOURCE
645 : :
646 : : function cheb_oracle(x, a, b, tol, nmax) result(n)
647 : :
648 : : real(dp) :: tol
649 : :
650 : : integer :: nmax
651 : : integer :: n, i
652 : : real(dp), intent(in) :: x, a, b
653 : : real(dp) :: y, xred, temp
654 : : real(dp) :: yim1
655 : :
656 : : ! *************************************************************************
657 : :
658 : : xred = (x-(a+b)/2)/(b-a)*2
659 : : y = xred
660 : : yim1 = one
661 : :
662 : : n = nmax
663 : : if(1/(y**2) < tol) then
664 : : n = 1
665 : : else
666 : : do i=2, nmax-1
667 : : temp = y
668 : : y = 2*xred*y - yim1
669 : : yim1 = temp
670 : : if(1/(y**2) < tol) then
671 : : n = i
672 : : exit
673 : : end if
674 : : end do
675 : : end if
676 : :
677 : : end function cheb_oracle
678 : : !!***
679 : :
680 : : end module m_chebfi
681 : : !!***
|