Branch data Line data Source code
1 : : !!****m* ABINIT/m_opernlb_ylm_mv
2 : : !! NAME
3 : : !! m_opernlb_ylm_mv
4 : : !!
5 : : !! FUNCTION
6 : : !!
7 : : !! COPYRIGHT
8 : : !! Copyright (C) 2021-2026 ABINIT group (LB,MT)
9 : : !! This file is distributed under the terms of the
10 : : !! GNU General Public License, see ~abinit/COPYING
11 : : !! or http://www.gnu.org/copyleft/gpl.txt .
12 : : !!
13 : : !! SOURCE
14 : :
15 : : #if defined HAVE_CONFIG_H
16 : : #include "config.h"
17 : : #endif
18 : :
19 : : #include "abi_common.h"
20 : :
21 : : module m_opernlb_ylm_mv
22 : :
23 : : use defs_basis
24 : : use m_abicore
25 : : use m_errors
26 : : #if defined HAVE_OPENMP
27 : : use OMP_LIB
28 : : #endif
29 : :
30 : : implicit none
31 : :
32 : : private
33 : : !!***
34 : :
35 : : public :: opernlb_ylm_mv
36 : : integer,public,save :: opernlb_mv_counter = -1
37 : : integer,public,save :: opernlb_mv_dgemv_counter = -1
38 : : !!***
39 : :
40 : : contains
41 : : !!***
42 : :
43 : : !!****f* ABINIT/opernlb_ylm_mv
44 : : !! NAME
45 : : !! opernlb_ylm_mv
46 : : !!
47 : : !! FUNCTION
48 : : !! "matrix-vector" alternative implementation of "opernlrb_ylm".
49 : : !!
50 : : !! * Operate with the non-local part of the hamiltonian,
51 : : !! from projected scalars to reciprocal space.
52 : : !! * Operate with the non-local projectors and the overlap matrix,
53 : : !! from projected scalars to reciprocal space.
54 : : !!
55 : : !! The input is gxfac (gxfac_sij):
56 : : !! gxfac(lmn) = Sum_l'm'n' D_l'm'n'.<p_l'm'n|c> (or S_l'm'n' for gxfac_sij)
57 : : !! and here we compute :
58 : : !! Sum_lmn <g|p_lmn> gxfac(lmn) = 4pi/sqrt(vol) exp(-2pi.i.g.R) Sum_lmn (-i)^l f_nl(g).Y_lm(g) gxfac(lmn)
59 : : !! Here this is done in 3 steps:
60 : : !! (1) compute for every lmn : gxfac_(lmn) = 4pi/sqrt(vol).(-i)^l.gxfac(lmn)
61 : : !! (2) compute for every g : scal(g) = Sum_lmn f_nl(g).Y_lm(g).gxfac_(lmn)
62 : : !! (3) compute for every g : vect(g) = exp(-2pi.i.g.R).scal(g)
63 : : !!
64 : : !! Step (2) is a real-matrix/complex-vector multiplication, here two options are possible:
65 : : !! - case nloalg(1)=2 : compute the real and imaginary parts separately using two calls of DGMEV
66 : : !! - case nloalg(1)=3 : in order to read the matrix only once, we compute both real and imaginary parts at the same time "by hand"
67 : : !!
68 : : !! Depending on the achitecture and the available blas library, one option could be more interesting than an other...
69 : : !!
70 : : !! INPUTS
71 : : !! choice=chooses possible output (see below)
72 : : !! cplex=1 if <p_lmn|c> scalars are real (equivalent to istwfk>1)
73 : : !! 2 if <p_lmn|c> scalars are complex
74 : : !! cplex_fac=1 if gxfac scalars are real, 2 if gxfac scalars are complex
75 : : !! dimffnl=second dimension of ffnl
76 : : !! ffnl(npw,dimffnl,nlmn)= nonlocal quantities containing nonlocal form factors
77 : : !! gxfac(cplex_fac,nlmn,nincat,nspinor)= reduced projected scalars related to Vnl (NL operator)
78 : : !! gxfac_sij(cplex,nlmn,nincat,nspinor*(paw_opt/3))= reduced projected scalars related to Sij (overlap)
79 : : !! ia3=gives the number of the first atom in the subset presently treated
80 : : !! indlmn(6,nlmn)= array giving l,m,n,lm,ln,s for i=lmn
81 : : !! matblk=dimension of the array ph3d
82 : : !! nincat=number of atoms in the subset here treated
83 : : !! nlmn=number of (l,m,n) numbers for current type of atom
84 : : !! nloalg(3)=governs the choice of the algorithm for non-local operator.
85 : : !! npw=number of plane waves in reciprocal space
86 : : !! nspinor=number of spinorial components of the wavefunctions (on current proc)
87 : : !! paw_opt= define the nonlocal operator concerned with:
88 : : !! paw_opt=0 : Norm-conserving Vnl (use of Kleinman-Bylander ener.)
89 : : !! paw_opt=1 : PAW nonlocal part of H (use of Dij coeffs)
90 : : !! paw_opt=2 : PAW: (Vnl-lambda.Sij) (Sij=overlap matrix)
91 : : !! paw_opt=3 : PAW overlap matrix (Sij)
92 : : !! paw_opt=4 : both PAW nonlocal part of H (Dij) and overlap matrix (Sij)
93 : : !! ph3d(2,npw,matblk)=three-dimensional phase factors
94 : : !! ucvol=unit cell volume (bohr^3)
95 : : !!
96 : : !! OUTPUT
97 : : !! (see side effects)
98 : : !!
99 : : !! SIDE EFFECTS
100 : : !! --if (paw_opt=0)
101 : : !! vectout(2,npwout*my_nspinor*ndat)=result of the aplication of the concerned operator
102 : : !! or one of its derivatives to the input vect.
103 : : !! --if (paw_opt=0, 1 or 4)
104 : : !! vect(2,npwout*nspinor)=result of the aplication of the concerned operator
105 : : !! or one of its derivatives to the input vect.:
106 : : !! if (choice=1) <G|V_nonlocal|vect_in>
107 : : !! if (paw_opt=2)
108 : : !! vect(2,npwout*nspinor)=final vector in reciprocal space:
109 : : !! if (choice=1) <G|V_nonlocal-lamdba.(I+S)|vect_in> (note: not including <G|I|c>)
110 : : !! --if (paw_opt=3 or 4)
111 : : !! svect(2,npwout*nspinor)=result of the aplication of Sij (overlap matrix)
112 : : !! or one of its derivatives to the input vect.:
113 : : !! if (choice=1) <G|I+S|vect_in> (note: not including <G|I|c>)
114 : : !!
115 : : !! NOTES
116 : : !! 1-No openMP available for now
117 : : !! 2-Operate for one type of atom, and within this given type of atom,
118 : : !! for a subset of at most nincat atoms.
119 : : !! 3-projector derivatives (abs(choice)>1) are not implemented yet
120 : : !!
121 : : !! SOURCE
122 : :
123 : 0 : subroutine opernlb_ylm_mv(choice,cplex,cplex_fac,&
124 : 0 : & dimffnl,ffnl,gxfac,gxfac_sij,&
125 : 0 : & ia3,indlmn,matblk,nincat,nlmn,nloalg,npw,&
126 [ # # # # ]: 0 : & nspinor,paw_opt,ph3d,svect,ucvol,vect)
127 : :
128 : : !Arguments ------------------------------------
129 : : !scalars
130 : : integer,intent(in) :: choice,cplex,cplex_fac,dimffnl,ia3,matblk,nincat
131 : : integer,intent(in) :: nlmn,npw,nspinor,paw_opt
132 : : real(dp),intent(in) :: ucvol
133 : : !arrays
134 : : integer,intent(in) :: indlmn(6,nlmn),nloalg(3)
135 : : real(dp),intent(in),target :: ffnl(npw,dimffnl,nlmn)
136 : : real(dp),intent(in) :: gxfac(cplex_fac,nlmn,nincat,nspinor)
137 : : real(dp),intent(in) :: gxfac_sij(cplex,nlmn,nincat,nspinor*(paw_opt/3))
138 : : real(dp),intent(in) :: ph3d(2,npw,matblk)
139 : : real(dp),intent(inout) :: svect(:,:),vect(:,:)
140 : : !Local variables-------------------------------
141 : : !Arrays
142 : : !scalars
143 : : logical :: use_dgemv
144 : : integer :: ia,iaph3d
145 : : integer :: il,ilmn,ipw,jpw,ipwshft,ispinor
146 : : real(dp) :: buffer_r,buffer_i,wt
147 : : !arrays
148 : : ! real(dp) :: tsec(2)
149 : 0 : real(dp) :: gxfac_(nlmn,2),gxfacs_(nlmn,2)
150 : 0 : real(dp),allocatable :: scalr(:),scali(:)
151 : 0 : real(dp),pointer :: ffnl_loc(:,:)
152 : : complex(dp) :: ctmp, cil(4)
153 : :
154 : : ! *************************************************************************
155 : :
156 : : DBG_ENTER("COLL")
157 : :
158 : : !Some checks
159 : : ! nthreads=1
160 : : !#if defined HAVE_OPENMP
161 : : ! nthreads=OMP_GET_NUM_THREADS()
162 : : !#endif
163 : : ! if (nthreads>1) then
164 : : ! ABI_ERROR('Only nthreads=1 is available for now.')
165 : : ! end if
166 : :
167 : 0 : if (abs(choice)>1) then
168 : 0 : ABI_ERROR('Only abs(choice)<=1 is available for now.')
169 : : end if
170 [ # # ]: 0 : if (nloalg(1)<2.or.nloalg(1)>10) then
171 : 0 : ABI_ERROR('nloalg(1) should be between 2 or 10.')
172 : : end if
173 : :
174 [ # # ]: 0 : use_dgemv = nloalg(1)==2.or.nloalg(1)==6.or.nloalg(1)==10
175 : : if (use_dgemv) then
176 [ # # ]: 0 : if(opernlb_mv_dgemv_counter>=0) then
177 : 0 : opernlb_mv_dgemv_counter = opernlb_mv_dgemv_counter + 1
178 [ # # ]: 0 : if (paw_opt==4) opernlb_mv_dgemv_counter = opernlb_mv_dgemv_counter + 1
179 : : end if
180 : : else
181 [ # # ]: 0 : if(opernlb_mv_counter>=0) then
182 : 0 : opernlb_mv_counter = opernlb_mv_counter + 1
183 [ # # ]: 0 : if (paw_opt==4) opernlb_mv_counter = opernlb_mv_counter + 1
184 : : end if
185 : : end if
186 : :
187 : : !Inits
188 : 0 : wt=four_pi/sqrt(ucvol)
189 : :
190 : 0 : ffnl_loc => ffnl(:,1,:)
191 : :
192 : :
193 [ # # # # : 0 : ABI_MALLOC(scalr,(npw))
# # # # #
# # # ]
194 [ # # # # : 0 : ABI_MALLOC(scali,(npw))
# # # # ]
195 : :
196 : : !$OMP PARALLEL PRIVATE(buffer_r,buffer_i,cil,il,ilmn,ipw,jpw,ctmp), &
197 : : !$OMP PRIVATE(ispinor,ipwshft,ia,iaph3d,gxfac_,gxfacs_)
198 : :
199 : : ! (-i)^l
200 : 0 : cil(1) = ( 1.0_DP, 0.0_DP) * wt
201 : 0 : cil(2) = ( 0.0_DP,-1.0_DP) * wt
202 : 0 : cil(3) = (-1.0_DP, 0.0_DP) * wt
203 : 0 : cil(4) = ( 0.0_DP, 1.0_DP) * wt
204 : :
205 : : ! if (paw_opt/=3) then
206 : : ! ABI_MALLOC(gxfac_,(nlmn,2))
207 : : ! end if
208 : : ! if (paw_opt>=3) then
209 : : ! ABI_MALLOC(gxfacs_,(nlmn,2))
210 : : ! end if
211 : :
212 : : !Loop on spinorial components
213 [ # # ]: 0 : do ispinor=1,nspinor
214 : 0 : ipwshft=(ispinor-1)*npw
215 : :
216 : : ! Loop on atoms (blocking)
217 [ # # ]: 0 : do ia=1,nincat
218 [ # # ]: 0 : iaph3d=ia;if (nloalg(2)>0) iaph3d=ia+ia3-1
219 : : ! Step (1) : scale gxfac with 4pi/sqr(omega).(-i)^l
220 [ # # ]: 0 : if (paw_opt/=3) then
221 [ # # ]: 0 : if (cplex_fac==2) then
222 [ # # ]: 0 : do ilmn=1,nlmn
223 : 0 : il=mod(indlmn(1,ilmn),4)+1
224 : 0 : ctmp = cil(il) * cmplx( gxfac(1,ilmn,ia,ispinor), gxfac(2,ilmn,ia,ispinor), kind=DP )
225 : 0 : gxfac_(ilmn,1) = real(ctmp)
226 : 0 : gxfac_(ilmn,2) = aimag(ctmp)
227 : : end do
228 [ # # ]: 0 : else if (cplex_fac==1) then
229 [ # # ]: 0 : do ilmn=1,nlmn
230 : 0 : il=mod(indlmn(1,ilmn),4)+1
231 : 0 : ctmp = cil(il) * gxfac(1,ilmn,ia,ispinor)
232 : 0 : gxfac_(ilmn,1) = real(ctmp)
233 : 0 : gxfac_(ilmn,2) = aimag(ctmp)
234 : : end do
235 : : else
236 : 0 : ABI_BUG('Error : should not be possible to be here')
237 : : end if
238 : : end if
239 : :
240 : : ! Step (1) bis: Scale gxfac_sij with 4pi/sqr(omega).(-i)^l
241 [ # # ]: 0 : if (paw_opt>=3) then
242 [ # # ]: 0 : if (cplex==2) then
243 [ # # ]: 0 : do ilmn=1,nlmn
244 : 0 : il=mod(indlmn(1,ilmn),4)+1
245 : 0 : ctmp = cil(il) * cmplx( gxfac_sij(1,ilmn,ia,ispinor), gxfac_sij(2,ilmn,ia,ispinor), kind=DP )
246 : 0 : gxfacs_(ilmn,1) = real(ctmp)
247 : 0 : gxfacs_(ilmn,2) = aimag(ctmp)
248 : : end do
249 [ # # ]: 0 : else if (cplex==1) then
250 [ # # ]: 0 : do ilmn=1,nlmn
251 : 0 : il=mod(indlmn(1,ilmn),4)+1
252 : 0 : ctmp = cil(il) * gxfac_sij(1,ilmn,ia,ispinor)
253 : 0 : gxfacs_(ilmn,1) = real(ctmp)
254 : 0 : gxfacs_(ilmn,2) = aimag(ctmp)
255 : : end do
256 : : else
257 : 0 : ABI_BUG('Error : should not be possible to be here')
258 : : end if
259 : : end if
260 : :
261 : : ! Compute <g|Vnl|c> (or derivatives) for each plane wave:
262 [ # # ]: 0 : if (paw_opt/=3) then
263 : :
264 : : ! Step (2) scal(g) = Sum_lmn f_nl(g).Y_lm(g).gxfac_(lmn)
265 [ # # ]: 0 : if (use_dgemv) then
266 [ # # ]: 0 : call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfac_(:,1),1,0.0_DP,scalr,1)
267 [ # # ]: 0 : call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfac_(:,2),1,0.0_DP,scali,1)
268 : : else
269 : : ! scalr(:) = zero
270 : : ! scali(:) = zero
271 : : ! do ilmn=1,nlmn
272 : : ! do ipw=1,npw
273 : : ! scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
274 : : ! scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
275 : : ! end do
276 : : ! end do
277 : : !$OMP DO
278 [ # # ]: 0 : do ipw=1,npw
279 : : buffer_r = zero
280 : : buffer_i = zero
281 [ # # ]: 0 : do ilmn=1,nlmn
282 : 0 : buffer_r = buffer_r + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
283 : 0 : buffer_i = buffer_i + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
284 : : ! scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,1)
285 : : ! scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfac_(ilmn,2)
286 : : end do
287 : 0 : scalr(ipw) = buffer_r
288 : 0 : scali(ipw) = buffer_i
289 : : end do
290 : : !$OMP END DO
291 : : end if
292 : :
293 : : ! Step (3) : vect(g) = exp(-2pi.i.g.R).scal(g)
294 : : !$OMP DO
295 [ # # ]: 0 : do ipw=1,npw
296 : 0 : jpw=ipw+ipwshft
297 : 0 : vect(1,jpw)=vect(1,jpw)+scalr(ipw)*ph3d(1,ipw,iaph3d)+scali(ipw)*ph3d(2,ipw,iaph3d)
298 : 0 : vect(2,jpw)=vect(2,jpw)-scalr(ipw)*ph3d(2,ipw,iaph3d)+scali(ipw)*ph3d(1,ipw,iaph3d)
299 : : end do
300 : : !$OMP END DO
301 : :
302 : : end if
303 : :
304 : : ! Compute <g|S|c> (or derivatives) for each plane wave:
305 [ # # ]: 0 : if (paw_opt>=3) then
306 : :
307 : : ! Step (2) (bis) scal(g) = Sum_lmn f_nl(g).Y_lm(g).gxfacs_(lmn)
308 [ # # ]: 0 : if (nloalg(1)==3) then
309 : : ! scalr(:) = zero
310 : : ! scali(:) = zero
311 : : ! do ilmn=1,nlmn
312 : : ! do ipw=1,npw
313 : : ! scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
314 : : ! scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
315 : : ! end do
316 : : ! end do
317 : : !$OMP DO
318 [ # # ]: 0 : do ipw=1,npw
319 : : buffer_r = zero
320 : : buffer_i = zero
321 [ # # ]: 0 : do ilmn=1,nlmn
322 : 0 : buffer_r = buffer_r + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
323 : 0 : buffer_i = buffer_i + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
324 : : ! scalr(ipw) = scalr(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,1)
325 : : ! scali(ipw) = scali(ipw) + ffnl_loc(ipw,ilmn) * gxfacs_(ilmn,2)
326 : : end do
327 : 0 : scalr(ipw) = buffer_r
328 : 0 : scali(ipw) = buffer_i
329 : : end do
330 : : !$OMP END DO
331 [ # # ]: 0 : else if (nloalg(1)==2) then
332 [ # # ]: 0 : call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfacs_(:,1),1,0.0_DP,scalr,1)
333 [ # # ]: 0 : call DGEMV('N',npw,nlmn,1.0_DP,ffnl_loc,npw,gxfacs_(:,2),1,0.0_DP,scali,1)
334 : : end if
335 : :
336 : : ! Step (3) (bis) : svect(g) = exp(-2pi.i.g.R).scal(g)
337 : : !$OMP DO
338 [ # # ]: 0 : do ipw=1,npw
339 : 0 : jpw=ipw+ipwshft
340 : 0 : svect(1,jpw)=svect(1,jpw)+scalr(ipw)*ph3d(1,ipw,iaph3d)+scali(ipw)*ph3d(2,ipw,iaph3d)
341 : 0 : svect(2,jpw)=svect(2,jpw)-scalr(ipw)*ph3d(2,ipw,iaph3d)+scali(ipw)*ph3d(1,ipw,iaph3d)
342 : : end do
343 : : !$OMP END DO
344 : :
345 : : end if
346 : :
347 : : ! End loop on atoms
348 : : end do
349 : : end do ! End loop on spinors
350 : : ! if (paw_opt/=3) then
351 : : ! ABI_FREE(gxfac_)
352 : : ! end if
353 : : ! if (paw_opt>=3) then
354 : : ! ABI_FREE(gxfacs_)
355 : : ! end if
356 : : !$OMP END PARALLEL
357 : :
358 [ # # ]: 0 : ABI_FREE(scalr)
359 [ # # ]: 0 : ABI_FREE(scali)
360 : :
361 : :
362 : : DBG_EXIT("COLL")
363 : :
364 [ # # ]: 0 : end subroutine opernlb_ylm_mv
365 : : !!***
366 : :
367 : : end module m_opernlb_ylm_mv
368 : : !!***
|