Line data Source code
1 : !!****m* ABINIT/m_gsphere
2 : !! NAME
3 : !! m_gsphere
4 : !!
5 : !! FUNCTION
6 : !! The Gsphere data type defines the set of G-vectors
7 : !! centered on Gamma used to describe (chi0|epsilon|W) in the GW code.
8 : !! Note that, unlike the kg_k arrays used for wavefunctions, here the
9 : !! G-vectors are ordered in shells (increasing length). Moreover
10 : !! the sphere can be enlarged to take into account umklapps for which
11 : !! one need the knowledge of several quantities at G-G0.
12 : !!
13 : !! COPYRIGHT
14 : !! Copyright (C) 1999-2026 ABINIT group (MG, GMR, VO, LR, RWG, MT, XG)
15 : !! This file is distributed under the terms of the
16 : !! GNU General Public License, see ~abinit/COPYING
17 : !! or http://www.gnu.org/copyleft/gpl.txt .
18 : !!
19 : !! SOURCE
20 :
21 : #if defined HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "abi_common.h"
26 :
27 : module m_gsphere
28 :
29 : use defs_basis
30 : use m_abicore
31 : use m_errors
32 : use m_sort
33 :
34 : use defs_abitypes, only : MPI_type
35 : use m_fstrings, only : sjoin, itoa
36 : use m_numeric_tools, only : bisect
37 : use m_geometry, only : normv
38 : use m_crystal, only : crystal_t
39 : use m_fftcore, only : kpgsph, kgindex, sphereboundary
40 : use m_mpinfo, only : destroy_mpi_enreg, initmpi_seq
41 :
42 : implicit none
43 :
44 : private
45 :
46 : ! Low-level procedures.
47 : public :: merge_and_sort_kg ! Merges a set of k-centered G-spheres of cutoff ecut. Return a Gamma-centered G-spheres.
48 : public :: table_gbig2kg ! Associate the kg_k set of G-vectors with Gamma-centered G-sphere.
49 : public :: get_irredg ! Given a set of G vectors, find the set of G"s generating the others by symmetry.
50 : public :: merge_kgirr ! Merge a list of irreducible G vectors (see routine for more info)
51 : public :: setshells ! Set consistently the number of shells, the number of plane-waves, and the energy cut-off
52 : public :: kg_map ! Compute the mapping between two lists of g-vectors.
53 : public :: make_istwfk_table
54 : public :: getkpgnorm ! Compute the norms of the k+G vectors
55 : public :: symg
56 : !!***
57 :
58 : !----------------------------------------------------------------------
59 :
60 : !!****t* m_gsphere/gsphere_t
61 : !! NAME
62 : !! gsphere_t
63 : !!
64 : !! FUNCTION
65 : !! The gsphere_t data type contains information related to the set of G vectors
66 : !! used during a screening or a GW calculation, as well as symmetry tables relating
67 : !! these vectors. Presently the following quantities are stored
68 : !!
69 : !! 1) The reduced coordinates of the G vectors (arrays gvec)
70 : !! 2) Tables giving the correspondence between a G-vector and its rotated image
71 : !! through a symmetry operation in reciprocal space.
72 : !! 3) List of the irreducible G pairs
73 : !! 4) Tables giving, for each pair in the full reciprocal space, the corresponding
74 : !! irreducible pair as well as the symmetry operation in reciprocal space
75 : !!
76 : !! Note that, unlike the GS part, the basis set does not depend on the k-point.
77 : !!
78 : !! NOTES
79 : !!
80 : !! To indicate the indices in the arrays grottb, grottbm1 we use the following notation:
81 : !!
82 : !! g defines the index of the reciprocal lattice vector in the array gvec
83 : !! s indicates the index of the symmetry operation in reciprocal space
84 : !! i can be one or two. 1 is used to indicate the identity operator
85 : !!
86 : !! SOURCE
87 :
88 : type,public :: gsphere_t
89 :
90 : integer :: ng
91 : ! Total number of G vectors in the sphere taking into account umklapps
92 : ! it defines the size of the array gvec and it accounts for possible umklapps for which
93 : ! one has to shift the sphere.
94 :
95 : ! TODO: The sphere should be enlarged in gpairs_init using mg0 and (ecut|ng) as input.
96 : ! For the time being we keep the old implementation.
97 : !%integer :: ng_eff
98 : ! Effective number of G vectors, i.e. the number of G in the smaller sphere without umklapps.
99 : ! ng_eff<=ng and should be used to loop over the elements of (chi0|epsilon|W).
100 : !
101 : ! TODO: Add info on FFT including zero-padding algorithm.
102 : ! table must be recalculated for each G0 and rho_tw_g should accept gpshere in input.
103 :
104 : integer :: nsh ! Number of shells
105 : integer :: nsym ! The number of symmetry operations
106 : integer :: timrev ! 2 if time-reversal is used, 1 otherwise
107 : integer :: istwfk=1 ! Storage mode. At present time-reversal is not used.
108 :
109 : !integer :: mg0(3)=0
110 : ! For each reduced direction gives the max G0 component to account for umklapp processes.
111 :
112 : real(dp) :: ecut
113 : ! Cutoff energy of the sphere.
114 :
115 : real(dp) :: gmet(3,3)
116 : ! Reciprocal space metric ($\textrm{bohr}^{-2}$).
117 :
118 : real(dp) :: gprimd(3,3)
119 : ! Dimensional reciprocal space primitive translations (bohr^{-1})
120 :
121 : integer,allocatable :: g2sh(:)
122 : ! g2sh(ng)
123 : ! For each G, it gives the index of the shell to which it belongs.
124 :
125 : integer,allocatable :: gvec(:,:)
126 : ! gvec(3,ng)
127 : ! Reduced coordinates of G vectors.
128 :
129 : integer,allocatable :: g2mg(:)
130 : ! g2mg(ng)
131 : ! Correspondence G --> -G
132 :
133 : integer,allocatable :: rottb(:,:,:)
134 : ! rottb(ng,timrev,nsym)
135 : ! rottb(G,I,S) is the index of (SI) G in the array gvec
136 : ! where I is either the identity or the inversion.
137 :
138 : integer,allocatable :: rottbm1(:,:,:)
139 : ! rottb(ng,timrev,nsym)
140 : ! rottbm1(G,I,S) is the index of IS{^-1} G in the array gvec
141 :
142 : integer,allocatable :: shlim(:)
143 : ! shlim(nsh+1)
144 : ! Index of the first G vector in each shell, =ng+1 for nsh+1
145 :
146 : real(dp),allocatable :: shlen(:)
147 : ! shlen(nsh)
148 : ! Radius of each shell.
149 :
150 : !TODO switch to dpc
151 : complex(gwp),allocatable :: phmGt(:,:)
152 : ! phmGt(ng,nsym)
153 : ! Phase factor e^{-i2\pi(G.\tau)} where $\tau$ is the fractional translation associated to isym.
154 :
155 : complex(gwp),allocatable :: phmSGt(:,:)
156 : ! phmSGt(ng,nsym)
157 : ! Phase factor e^{-i2\pi(SG.\tau)} where S is one of the symmetry properties in reciprocal space.
158 :
159 : contains
160 :
161 : procedure :: init => gsph_init ! Initialize the G-sphere.
162 : procedure :: fft_tabs => gsph_fft_tabs ! Returns useful tables for FFT (with or without padding).
163 : procedure :: in_fftbox => gsph_in_fftbox ! Initialize the largest Gsphere contained in the FFT box.
164 : procedure :: print => gsph_print ! Printout of basic dimensions.
165 : procedure :: free => gsph_free ! Free memory allocated in the object.
166 : procedure :: g_idx => gsph_g_idx ! Returns the index of G from its reduced coordinates.
167 : procedure :: gmg_idx => gsph_gmg_idx ! Returns the index of G1-G2 from their indices
168 : procedure :: gmg_fftidx => gsph_gmg_fftidx ! Returns the index of G1-G2 in the FFT mesh defined by ngfft.
169 : procedure :: extend => gsph_extend ! Construct a new gsphere_t with a larger cutoff energy
170 :
171 : end type gsphere_t
172 : !!***
173 :
174 : CONTAINS !=================================================================================
175 : !!***
176 :
177 : !!****f* m_gsphere/setup_G_rotation
178 : !! NAME
179 : !! setup_G_rotation
180 : !!
181 : !! FUNCTION
182 : !! Set up tables indicating rotation of G-vectors.
183 : !!
184 : !! INPUTS
185 : !! nsym=Number of symmetry operations.
186 : !! symrec(3,3,nsym)=Symmetry operations in reciprocal space.
187 : !! timrev=2 if time reversal can be used, 1 otherwise.
188 : !! npw=Number of planewaves in the sphere.
189 : !! gvec(3,npw)=Coordinates of plane waves, supposed to be ordered in increasing modulus
190 : !! g2sh(npw)=For each G, it gives the index of the shell to which it belongs.
191 : !! nsh=Number of shells
192 : !! shlim(nsh+1)=Index of the first G vector in each shell, =npw+1 for nsh+1
193 : !!
194 : !! OUTPUT
195 : !! grottb (npw,2,nsym)= grottb(G,I,S) is the index of (SI) G in the array gvec.
196 : !! grottbm1(npw,2,nsym)= index of IS^{-1} G.
197 : !!
198 : !! NOTES:
199 : !! I is either the identity or the inversion (time reversal in reciprocal space).
200 : !! S is one of the symmetry operation in reciprocal space belonging to the Space group.
201 : !!
202 : !! SOURCE
203 :
204 1066 : subroutine setup_G_rotation(nsym,symrec,timrev,npw,gvec,g2sh,nsh,shlim,grottb,grottbm1)
205 :
206 : !Arguments ------------------------------------
207 : !scalars
208 : integer,intent(in) :: npw,nsh,nsym,timrev
209 : !arrays
210 : integer,intent(in) :: g2sh(npw),gvec(3,npw),shlim(nsh+1),symrec(3,3,nsym)
211 : integer,intent(inout) :: grottb (npw,timrev,nsym)
212 : integer,intent(inout) :: grottbm1(npw,timrev,nsym)
213 :
214 : !Local variables ------------------------------
215 : !scalars
216 : integer :: ee,ig1,ig2,ish1,isym,itim,ss
217 : logical :: found
218 : character(len=500) :: msg
219 : !arrays
220 : integer :: gbase(3),grot(3)
221 : !************************************************************************
222 :
223 : ! === Set up G-rotation table ===
224 716498 : do ig1=1,npw
225 715432 : ish1=g2sh(ig1) ; ss=shlim(ish1) ; ee=shlim(ish1+1)-1
226 2861728 : gbase(:)=gvec(:,ig1)
227 :
228 2141747 : do itim=1,timrev
229 35359841 : do isym=1,nsym
230 531506560 : grot=(3-2*itim)*MATMUL(symrec(:,:,isym),gbase)
231 : found=.FALSE.
232 : ! * Loop on the shell of ig1 to speed up the search.
233 2033871256 : do ig2=ss,ee
234 2296357632 : if (ALL(ABS(grot(:)-gvec(:,ig2))==0)) then
235 33219160 : found=.TRUE.
236 33219160 : grottb (ig1,itim,isym)=ig2
237 33219160 : grottbm1(ig2,itim,isym)=ig1
238 : end if
239 : end do
240 34644409 : if (.not.found) then
241 : write(msg,'(3a,i5,a,i5,1x,2(3i5,a),a,i3,a,i3)')&
242 0 : 'G-shell not closed',ch10,&
243 0 : ' Initial G vector ',ig1,'/',npw,gbase(:),' Rotated G vector ',grot(:),ch10,&
244 0 : ' Through sym ',isym,' and itim ',itim
245 0 : ABI_ERROR(msg)
246 : end if
247 : end do
248 : end do
249 :
250 : end do !ig1
251 :
252 1066 : end subroutine setup_G_rotation
253 : !!***
254 :
255 : !----------------------------------------------------------------------
256 :
257 : !!****f* m_gsphere/gsph_init
258 : !! NAME
259 : !! gsph_init
260 : !!
261 : !! FUNCTION
262 : !! Main creation method for the Gvectors data type
263 : !!
264 : !! INPUTS
265 : !! Cryst<crystal_t> = Info on unit cell and its symmetries
266 : !! ng=number of G vectors, needed only if gvec is passed.
267 : !! [gvec(3,ng)]=coordinates of G vectors
268 : !! [ecut]=Cutoff energy for G-sphere. gvec and ecut are mutually exclusive.
269 : !!
270 : !! OUTPUT
271 : !! Gsph<gsphere_t>=Data type containing information related to the set of G vectors
272 : !! completely initialized in output.
273 : !!
274 : !! NOTES
275 : !! gvec are supposed to be ordered with increasing norm.
276 : !!
277 : !! SOURCE
278 :
279 2026 : subroutine gsph_init(Gsph, Cryst, ng, gvec, ecut)
280 :
281 : !Arguments ------------------------------------
282 : !scalars
283 : class(gsphere_t),intent(out) :: Gsph
284 : integer,intent(in) :: ng
285 : real(dp),optional,intent(in) :: ecut
286 : type(crystal_t),target,intent(in) :: Cryst
287 :
288 : !arrays
289 : integer,optional,intent(in) :: gvec(3,ng)
290 : !Local variables-------------------------------
291 : !scalars
292 : integer,parameter :: nkpt1=1
293 : integer :: ig,isearch,img,ish,isym,nsh,nsym,timrev,pinv,g1,g2,g3,ss,ee
294 : real(dp) :: eps,norm,norm_old,max_ecut,gsq
295 : !arrays
296 : real(dp),parameter :: k_gamma(3)=(/zero,zero,zero/)
297 : integer :: sg(3),gsearch(3)
298 1066 : integer,allocatable :: shlim(:)
299 1066 : integer,pointer :: symrec(:,:,:),gvec_ptr(:,:)
300 : real(dp) :: kptns1(3,nkpt1)
301 1066 : real(dp),allocatable :: shlen(:)
302 1066 : real(dp),pointer :: tnons(:,:)
303 : !************************************************************************
304 :
305 : DBG_ENTER("COLL")
306 :
307 : ! Copy info on symmetries
308 1066 : nsym = Cryst%nsym
309 1066 : timrev = Cryst%timrev
310 1066 : symrec => Cryst%symrec
311 1066 : tnons => Cryst%tnons
312 :
313 : ! Initialize the object
314 1066 : Gsph%istwfk = 1 ! Time reversal is not used here.
315 1066 : Gsph%nsym = nsym
316 1066 : Gsph%timrev = timrev
317 :
318 13858 : Gsph%gmet = Cryst%gmet
319 13858 : Gsph%gprimd = Cryst%gprimd
320 :
321 1066 : if (PRESENT(gvec)) then
322 960 : if (PRESENT(ecut)) then
323 0 : ABI_BUG("ecut cannot be present when gvec is used")
324 : end if
325 960 : Gsph%ng= ng
326 2880 : ABI_MALLOC(Gsph%gvec,(3,ng))
327 1931848 : Gsph%gvec=gvec
328 : !
329 : ! Calculate cutoff energy of the sphere.
330 : max_ecut=-one
331 483442 : do ig=1,ng
332 482482 : g1=gvec(1,ig)
333 482482 : g2=gvec(2,ig)
334 482482 : g3=gvec(3,ig)
335 : gsq= Cryst%gmet(1,1)*g1**2+Cryst%gmet(2,2)*g2**2+Cryst%gmet(3,3)*g3**2+ &
336 482482 : two*(Cryst%gmet(1,2)*g1*g2+Cryst%gmet(1,3)*g1*g3+Cryst%gmet(2,3)*g2*g3)
337 483442 : max_ecut=MAX(max_ecut,gsq)
338 : end do
339 960 : max_ecut=two*max_ecut*pi**2
340 960 : Gsph%ecut= max_ecut
341 :
342 : else
343 : ! To be consistent with the previous implementation.
344 : !ABI_WARNING("Init from ecut has to be tested")
345 : !call setshells(ecut,npw,nsh,nsym,Cryst%gmet,Cryst%gprimd,Cryst%symrel,tag,Cryst%ucvol)
346 106 : Gsph%ecut = ecut
347 106 : pinv=+1; kptns1(:,1)=k_gamma
348 106 : call merge_and_sort_kg(nkpt1,kptns1,ecut,Cryst%nsym,pinv,Cryst%symrel,Cryst%gprimd,gvec_ptr,0)
349 106 : Gsph%ng = SIZE(gvec_ptr,DIM=2)
350 318 : ABI_MALLOC(Gsph%gvec, (3,Gsph%ng))
351 932012 : Gsph%gvec = gvec_ptr
352 106 : ABI_FREE(gvec_ptr)
353 : end if
354 :
355 : ! Calculate phase exp{-i2\pi G.\tau}
356 4264 : ABI_MALLOC(Gsph%phmGt, (Gsph%ng, nsym))
357 43674 : do isym=1,nsym
358 16763342 : do ig=1,Gsph%ng
359 66921280 : Gsph%phmGt(ig, isym) = EXP(-j_dpc*two_pi*DOT_PRODUCT(Gsph%gvec(:,ig), tnons(:,isym)))
360 : end do
361 : end do
362 : !
363 : ! === Calculate phase phsgt= exp{-i2\pi SG\cdot t} ===
364 : ! TODO Here we can store only one of this arrays but I have to rewrite screeening!
365 3198 : ABI_MALLOC(Gsph%phmSGt,(Gsph%ng,nsym))
366 716498 : do ig=1,Gsph%ng
367 17436166 : do isym=1,nsym
368 518309708 : sg=MATMUL(symrec(:,:,isym),Gsph%gvec(:,ig))
369 67594104 : Gsph%phmSGt(ig,isym)=EXP(-j_dpc*two_pi*DOT_PRODUCT(sg,tnons(:,isym)))
370 : end do
371 : end do
372 : !
373 : ! === Calculate number of shells and corresponding starting index ===
374 : ! * Shells are useful to speed up search algorithms see e.g setup_G_rotation.
375 : ! * The last shell ends at ng+1, thus gvec is supposed to be closed.
376 :
377 4264 : ABI_CHECK(ALL(Gsph%gvec(1:3,1)==0), 'First G must be 0')
378 :
379 3198 : ABI_MALLOC(Gsph%g2sh,(Gsph%ng))
380 1066 : Gsph%g2sh(1)=1 ! This table is useful if we dont loop over shell
381 :
382 : ! For each shell, gives the index of the initial G-vector.
383 3198 : ABI_MALLOC(shlim,(Gsph%ng+1))
384 1066 : shlim(1)=1
385 :
386 : ! For each shell, gives the radius of the shell.
387 3198 : ABI_MALLOC(shlen,(Gsph%ng))
388 1066 : shlen(1)=zero
389 :
390 1066 : nsh=1; norm_old=zero
391 715432 : do ig=2,Gsph%ng
392 13572954 : norm=two_pi*SQRT(DOT_PRODUCT(Gsph%gvec(:,ig),MATMUL(Cryst%gmet,Gsph%gvec(:,ig))))
393 714366 : eps=norm*tol8
394 714366 : if (ABS(norm-norm_old)>eps) then
395 19085 : norm_old = norm; nsh = nsh + 1
396 19085 : shlim(nsh)=ig
397 19085 : shlen(nsh)=norm
398 : end if
399 715432 : Gsph%g2sh(ig)=nsh
400 : end do
401 1066 : shlim(nsh+1)=Gsph%ng+1
402 :
403 : ! Save info on the shells
404 1066 : Gsph%nsh = nsh
405 3198 : ABI_MALLOC(Gsph%shlim, (nsh+1))
406 23349 : Gsph%shlim = shlim(1:nsh+1)
407 3198 : ABI_MALLOC(Gsph%shlen, (nsh ))
408 22283 : Gsph%shlen = shlen(1:nsh)
409 1066 : ABI_FREE(shlim)
410 1066 : ABI_FREE(shlen)
411 :
412 : ! Calculate tables for rotated G"s
413 5330 : ABI_MALLOC(Gsph%rottb , (Gsph%ng,timrev,nsym))
414 4264 : ABI_MALLOC(Gsph%rottbm1, (Gsph%ng,timrev,nsym))
415 :
416 : call setup_G_rotation(nsym, symrec, timrev, Gsph%ng, Gsph%gvec,&
417 1066 : Gsph%g2sh, Gsph%nsh, Gsph%shlim, Gsph%rottb, Gsph%rottbm1)
418 :
419 : ! Store Mapping G --> -G
420 : ! (we use a specialized table instead of rootb since rottb assumes time-reversal symmetry.
421 3198 : ABI_MALLOC(gsph%g2mg, (gsph%ng))
422 :
423 716498 : do ig=1,gsph%ng
424 715432 : ish=gsph%g2sh(ig)
425 715432 : ss=gsph%shlim(ish); ee=gsph%shlim(ish+1)-1
426 2861728 : gsearch = -gsph%gvec(:,ig)
427 25258959 : img = 0
428 : ! Loop on shells to speed up the search.
429 25258959 : do isearch=ss,ee
430 29266560 : if (all(gsph%gvec(:,isearch) == gsearch)) then
431 : img = isearch; exit
432 : end if
433 : end do
434 715432 : if (img==0) ABI_ERROR("Cannot find -G in G-sphere!")
435 716498 : gsph%g2mg(ig) = img
436 : end do
437 :
438 : !call Gsph%print(unit=std_out,prtvol=1)
439 : DBG_EXIT("COLL")
440 :
441 2026 : end subroutine gsph_init
442 : !!***
443 :
444 : !----------------------------------------------------------------------
445 :
446 : !!****f* m_gsphere/gsph_fft_tabs
447 : !! NAME
448 : !! gsph_fft_tabs
449 : !!
450 : !! FUNCTION
451 : !!
452 : !! INPUTS
453 : !! Gsph<gsphere_t>=Info on the G-sphere
454 : !! g0(3)
455 : !! mgfft=MAXVAL(ngfft(1:3))
456 : !! ngfftf(18)=Info on the FFT mesh.
457 : !!
458 : !! OUTPUT
459 : !! use_padfft=1 if padded FFT can be used, 0 otherwise.
460 : !! gmg0_gbound(2*mgfft+8,2)=Tables for improved zero-padded FFTS. Calculated only if use_padfft==1
461 : !! gmg0_ifft(Gsph%ng)=Index of G-G0 in the FFT mesh defined by ngfft.
462 : !!
463 : !! NOTES
464 : !! The routine will stop if any G-G0 happens to be outside the FFT box.
465 : !!
466 : !! SOURCE
467 :
468 104432 : subroutine gsph_fft_tabs(Gsph, g0, mgfft, ngfft, use_padfft, gmg0_gbound, gmg0_ifft)
469 :
470 : !Arguments ------------------------------------
471 : !scalars
472 : class(gsphere_t),intent(in) :: Gsph
473 : integer,intent(in) :: mgfft
474 : integer,intent(out) :: use_padfft
475 : !arrays
476 : integer,intent(in) :: g0(3),ngfft(18)
477 : integer,intent(out) :: gmg0_gbound(2*mgfft+8,2),gmg0_ifft(Gsph%ng)
478 :
479 : !Local variables-------------------------------
480 : !scalars
481 : integer :: ig,ng,ierr
482 : character(len=500) :: msg
483 104432 : type(MPI_type) :: MPI_enreg_seq
484 : !arrays
485 104432 : integer,allocatable :: gmg0(:,:)
486 104432 : logical,allocatable :: kg_mask(:)
487 : ! *************************************************************************
488 :
489 417728 : if (mgfft/=MAXVAL(ngfft(1:3))) then
490 0 : ABI_ERROR("mgfft/-MAXVAL(ngfft(1:3)")
491 : end if
492 :
493 104432 : ng = Gsph%ng
494 :
495 104432 : ierr=0; use_padfft=0
496 313296 : ABI_MALLOC(gmg0,(3,ng))
497 6084642 : do ig=1,ng
498 23920840 : gmg0(:,ig) = Gsph%gvec(:,ig)-g0
499 : ! Consider possible wrap around errors.
500 47841680 : if ( ANY(gmg0(:,ig)>ngfft(1:3)/2) .or. ANY(gmg0(:,ig)<-(ngfft(1:3)-1)/2) ) then
501 : !gmg0_ifft(ig,ig01+mg0(1)+1,ig02+mg0(2)+1,ig03+mg0(3)+1) = 0
502 0 : write(std_out,*)" outside FFT box ",gmg0(:,ig)
503 0 : ierr=ierr+1
504 : end if
505 8066604 : if (ALL(gmg0(:,ig) == 0)) use_padfft=1
506 : end do
507 :
508 104432 : if (ierr/=0) then
509 0 : write(msg,'(a,i0,a)')'Found ',ierr,' G-G0 vectors falling outside the FFT box. This is not allowed '
510 0 : ABI_ERROR(msg)
511 : end if
512 : !
513 : ! Evaluate the tables needed for the padded FFT performed in rhotwg. Note that we have
514 : ! to pass G-G0 to sphereboundary instead of G as we need FFT results on the shifted G-sphere,
515 : ! If Gamma is not inside G-G0 one has to disable FFT padding as sphereboundary will give wrong tables.
516 104432 : if (use_padfft == 1) call sphereboundary(gmg0_gbound,1,gmg0,mgfft,ng)
517 :
518 104432 : call initmpi_seq(MPI_enreg_seq) ! No FFT parallelism.
519 104432 : call MPI_enreg_seq%distribfft%init_seq('c',ngfft(2),ngfft(3),'all')
520 :
521 313296 : ABI_MALLOC(kg_mask, (ng))
522 104432 : call kgindex(gmg0_ifft, gmg0, kg_mask, MPI_enreg_seq, ngfft, ng)
523 :
524 6084642 : ABI_CHECK(ALL(kg_mask),"FFT para not yet implemented")
525 104432 : ABI_FREE(kg_mask)
526 :
527 104432 : ABI_FREE(gmg0)
528 104432 : call destroy_mpi_enreg(MPI_enreg_seq)
529 :
530 104432 : end subroutine gsph_fft_tabs
531 : !!***
532 :
533 : !----------------------------------------------------------------------
534 :
535 : !!****f* m_gsphere/gsph_in_fftbox
536 : !! NAME
537 : !! gsph_in_fftbox
538 : !!
539 : !! FUNCTION
540 : !! Initialize the largest Gsphere contained in the FFT box.
541 : !!
542 : !! INPUTS
543 : !! Cryst<crystal_t> = Info on unit cell and its symmetries.
544 : !! ngfft(18)=Info on the FFT box.
545 : !!
546 : !! OUTPUT
547 : !! Gsph<gsphere_t>=Data type containing information related to the set of G vectors
548 : !! completely initialized in output.
549 : !!
550 : !! SOURCE
551 :
552 39 : subroutine gsph_in_fftbox(Gsph, Cryst, ngfft)
553 :
554 : !Arguments ------------------------------------
555 : !scalars
556 : class(gsphere_t),intent(out) :: Gsph
557 : type(crystal_t),intent(in) :: Cryst
558 : !arrays
559 : integer,intent(in) :: ngfft(18)
560 :
561 : !Local variables-------------------------------
562 : !scalars
563 : integer :: dir1,dir2,dir3,npw,ig,i_st
564 : real(dp) :: ecut,trial_ene
565 : !arrays
566 : integer :: n1_max(3),n2_max(3),n3_max(3),vec(3)
567 39 : integer,allocatable :: gvec(:,:)
568 : !************************************************************************
569 :
570 : ! Find ecut for the largest G-sphere contained in the FFT box.
571 39 : n1_max(1) = -(ngfft(1)-1)/2
572 39 : n2_max(1) = -(ngfft(2)-1)/2
573 39 : n3_max(1) = -(ngfft(3)-1)/2
574 :
575 39 : n1_max(2) = 0
576 39 : n2_max(2) = 0
577 39 : n3_max(2) = 0
578 :
579 39 : n1_max(3) = ngfft(1)/2
580 39 : n2_max(3) = ngfft(2)/2
581 39 : n3_max(3) = ngfft(3)/2
582 :
583 39 : ecut = HUGE(one)
584 156 : do dir3=1,3
585 117 : vec(3) = n1_max(dir3)
586 507 : do dir2=1,3
587 351 : vec(2) = n2_max(dir2)
588 1521 : do dir1=1,3
589 1053 : vec(1) = n1_max(dir1)
590 1911 : if (ANY(vec/=0)) then
591 1014 : trial_ene = half * normv(vec,Cryst%gmet,"G")**2
592 1014 : ecut = MIN(ecut,trial_ene)
593 : !write(std_out,*)vec(:),trial_ene
594 : end if
595 : end do
596 : end do
597 : end do
598 : !
599 : ! Init sphere from ecut.
600 39 : call Gsph%init(Cryst, 0, ecut=ecut)
601 : !
602 : ! Make sure that Gsph does not contain G vectors outside the FFT box.
603 : ! kpgsph might return G whose energy is larger than the input ecut.
604 39 : npw = Gsph%ng
605 3013 : star_loop: do i_st=1,Gsph%nsh-1
606 159018 : do ig=Gsph%shlim(i_st),Gsph%shlim(i_st+1)
607 1251266 : if ( ANY(Gsph%gvec(:,ig)>ngfft(1:3)/2) .or. ANY(Gsph%gvec(:,ig)<-(ngfft(1:3)-1)/2) ) then
608 36 : npw = Gsph%shlim(i_st)-1 ! Gsph exceeds the FFT box. Only the shells up to npw will be used.
609 36 : EXIT star_loop
610 : end if
611 : end do
612 : end do star_loop
613 :
614 39 : if (npw<Gsph%ng) then
615 36 : ABI_COMMENT("Have to reinit Gpshere")
616 108 : ABI_MALLOC(gvec,(3,npw))
617 610328 : gvec = Gsph%gvec(:,1:npw)
618 36 : call Gsph%free()
619 36 : call Gsph%init(Cryst, npw, gvec=gvec)
620 36 : ABI_FREE(gvec)
621 : end if
622 :
623 39 : end subroutine gsph_in_fftbox
624 : !!***
625 :
626 : !----------------------------------------------------------------------
627 :
628 : !!****f* m_gsphere/gsph_print
629 : !! NAME
630 : !! gsph_print
631 : !!
632 : !! FUNCTION
633 : !! Print info on object.
634 : !!
635 : !! INPUTS
636 : !! unit=the unit number for output
637 : !! prtvol = verbosity level
638 : !!
639 : !! SOURCE
640 :
641 144 : subroutine gsph_print(Gsph, units, prtvol, header)
642 :
643 : !Arguments ------------------------------------
644 : !scalars
645 : class(gsphere_t),intent(in) :: Gsph
646 : integer,intent(in) :: units(:), prtvol
647 : character(len=*),optional,intent(in) :: header
648 :
649 : !Local variables-------------------------------
650 : !scalars
651 : integer :: ish, nsc
652 : real(dp) :: fact, kin
653 : character(len=500) :: msg
654 : ! *************************************************************************
655 :
656 72 : msg = ch10 // ' ==== Info on the G-sphere ==== ' // ch10
657 72 : if (present(header)) msg = ' ==== '//trim(adjustl(header))//' ==== '
658 72 : call wrtout(units, msg)
659 :
660 : write(msg,'(2(a,i8,a))')&
661 72 : ' Number of G vectors ... ',Gsph%ng,ch10,&
662 144 : ' Number of shells ...... ',Gsph%nsh,ch10
663 72 : call wrtout(units, msg)
664 :
665 80 : select case (Gsph%timrev)
666 : case (1)
667 8 : call wrtout(units, ' Time reversal symmetry cannot be used')
668 : case (2)
669 64 : call wrtout(units, ' Time reversal symmetry is used')
670 : case default
671 72 : ABI_BUG("Wrong timrev")
672 : end select
673 :
674 72 : if (prtvol /= 0) then
675 2 : fact = half*two_pi**2
676 2 : write(msg,'(a)')
677 2 : call wrtout(units, ' Shell Tot no. of Gs Cutoff [Ha]')
678 88 : do ish=1,Gsph%nsh
679 86 : nsc=Gsph%shlim(ish+1)-1
680 86 : kin=half*Gsph%shlen(ish)**2
681 86 : write(msg, '(2x,i4,10x,i6,5x,f8.3)')ish,nsc,kin
682 88 : call wrtout(units, msg)
683 : end do
684 2 : call wrtout(units, ch10)
685 : end if
686 :
687 72 : end subroutine gsph_print
688 : !!***
689 :
690 : !----------------------------------------------------------------------
691 :
692 : !!****f* m_gsphere/gsph_free
693 : !! NAME
694 : !! gsph_free
695 : !!
696 : !! FUNCTION
697 : !! Deallocate the memory in a gsphere_t data type.
698 : !!
699 : !! SOURCE
700 :
701 1949 : subroutine gsph_free(Gsph)
702 :
703 : !Arguments ------------------------------------
704 : class(gsphere_t),intent(inout) :: Gsph
705 : ! *************************************************************************
706 :
707 : DBG_ENTER("COLL")
708 :
709 : !@gsphere_t
710 :
711 : ! integer arrays.
712 1949 : ABI_SFREE(Gsph%g2sh)
713 1949 : ABI_SFREE(Gsph%gvec)
714 1949 : ABI_SFREE(Gsph%g2mg)
715 1949 : ABI_SFREE(Gsph%rottb)
716 1949 : ABI_SFREE(Gsph%rottbm1)
717 1949 : ABI_SFREE(Gsph%shlim)
718 :
719 1949 : ABI_SFREE(Gsph%shlen)
720 :
721 : ! complex arrays
722 1949 : ABI_SFREE(Gsph%phmGt)
723 1949 : ABI_SFREE(Gsph%phmSGt)
724 :
725 : DBG_EXIT("COLL")
726 :
727 1949 : end subroutine gsph_free
728 : !!***
729 :
730 : !----------------------------------------------------------------------
731 :
732 : !!****f* m_gsphere/gsph_g_idx
733 : !! NAME
734 : !! gsph_g_idx
735 : !!
736 : !! FUNCTION
737 : !! Return the index of G in the sphere. zero if not in the sphere
738 : !!
739 : !! INPUTS
740 : !! Gsph<gsphere_t>=Info on the G-sphere
741 : !! gg(3)=Reduced coordinates of the G-vector.
742 : !!
743 : !! NOTES
744 : !! The function assumes that the G-vectors are ordered with increasing length.
745 : !!
746 : !! SOURCE
747 :
748 0 : pure function gsph_g_idx(Gsph, gg) result(g_idx)
749 :
750 : !Arguments ------------------------------------
751 : !scalars
752 : class(gsphere_t),intent(in) :: Gsph
753 : integer :: g_idx
754 : !arrays
755 : integer,intent(in) :: gg(3)
756 :
757 : !Local variables-------------------------------
758 : !scalars
759 : integer :: ishbsc,igs,ige
760 : real(dp) :: glen
761 : logical :: found
762 : ! *************************************************************************
763 :
764 : ! Use shells and bisection to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
765 0 : glen = two_pi*SQRT(DOT_PRODUCT(gg,MATMUL(Gsph%gmet,gg)))
766 :
767 0 : ishbsc = bisect(Gsph%shlen,glen)
768 0 : if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! glen out of range.
769 0 : g_idx=0; RETURN
770 : end if
771 :
772 0 : igs = Gsph%shlim(ishbsc)
773 0 : ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
774 :
775 0 : g_idx=igs-1; found=.FALSE.
776 0 : do while (.not.found .and. g_idx<ige)
777 0 : g_idx=g_idx+1
778 0 : found=(ALL(Gsph%gvec(:,g_idx)==gg(:)))
779 : end do
780 0 : if (.not.found) g_idx=0
781 :
782 0 : end function gsph_g_idx
783 : !!***
784 :
785 : !----------------------------------------------------------------------
786 :
787 : !!****f* m_gsphere/gsph_gmg_idx
788 : !! NAME
789 : !! gsph_gmg_idx
790 : !!
791 : !! FUNCTION
792 : !! Return the index of G1-G2 in the sphere. zero if not in the sphere
793 : !!
794 : !! INPUTS
795 : !! Gsph<gsphere_t>=Info on the G-sphere
796 : !! ig1,ig2 index of g1 and g2 in the G-sphere.
797 : !!
798 : !! NOTES
799 : !! The function assumes that the G-vectors are ordered with increasing length.
800 : !!
801 : !! SOURCE
802 :
803 6422840 : pure function gsph_gmg_idx(Gsph, ig1, ig2) result(ig1mg2)
804 :
805 : !Arguments ------------------------------------
806 : !scalars
807 : class(gsphere_t),intent(in) :: Gsph
808 : integer,intent(in) :: ig1,ig2
809 : integer :: ig1mg2
810 :
811 : !Local variables-------------------------------
812 : !scalars
813 : integer :: ishbsc,igs,ige
814 : real(dp) :: difflen
815 : logical :: found
816 : !arrays
817 : integer :: g1mg2(3)
818 : ! *************************************************************************
819 :
820 25691360 : g1mg2 = Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
821 :
822 : ! Use shells and bisect to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
823 122033960 : difflen = two_pi*SQRT(DOT_PRODUCT(g1mg2,MATMUL(Gsph%gmet,g1mg2)))
824 :
825 : ! FIXME It seems bisect is not portable, on my laptop test v5/t72 the number of skipped G-vectors is > 0
826 6422840 : ishbsc = bisect(Gsph%shlen,difflen)
827 6422840 : if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! difflen out of range.
828 0 : ig1mg2=0; RETURN
829 : end if
830 :
831 6422840 : igs = Gsph%shlim(ishbsc)
832 6422840 : ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
833 :
834 6422840 : ig1mg2=igs-1; found=.FALSE.
835 78583046 : do while (.not.found .and. ig1mg2<ige)
836 72160206 : ig1mg2=ig1mg2+1
837 108457970 : found=(ALL(Gsph%gvec(:,ig1mg2)==g1mg2(:)))
838 : end do
839 6422840 : if (.not.found) ig1mg2=0
840 :
841 6422840 : end function gsph_gmg_idx
842 : !!***
843 :
844 : !----------------------------------------------------------------------
845 :
846 : !!****f* m_gsphere/gsph_gmg_fftidx
847 : !! NAME
848 : !! gsph_gmg_fftidx
849 : !!
850 : !! FUNCTION
851 : !! Return the index of G1-G2 in the FFT mesh defined by ngfft. zero if not found.
852 : !!
853 : !! INPUTS
854 : !! Gsph<gsphere_t>=Info on the G-sphere
855 : !! ig1,ig2 index of g1 and g2 in the G-sphere.
856 : !! ngfft(18)=Info on the FFT mesh.
857 : !!
858 : !! SOURCE
859 :
860 3586176 : pure function gsph_gmg_fftidx(Gsph, ig1, ig2, ngfft) result(fft_idx)
861 :
862 : !Arguments ------------------------------------
863 : !scalars
864 : class(gsphere_t),intent(in) :: Gsph
865 : integer,intent(in) :: ig1,ig2
866 : integer :: fft_idx
867 : !arrays
868 : integer,intent(in) :: ngfft(18)
869 :
870 : !Local variables-------------------------------
871 : !scalars
872 : integer :: id1,id2,id3
873 : !arrays
874 : integer :: g1mg2(3)
875 : ! *************************************************************************
876 :
877 14344704 : g1mg2(:)=Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
878 :
879 : ! Make sure G1-G2 is still in the FFT mesh.
880 : ! MODULO wraps G1-G2 in the FFT box but the Fourier components are not periodic!
881 28689408 : if (ANY(g1mg2(:)>ngfft(1:3)/2) .or. ANY(g1mg2(:)<-(ngfft(1:3)-1)/2)) then
882 3586176 : fft_idx=0; RETURN
883 : end if
884 :
885 3586176 : id1=MODULO(g1mg2(1),ngfft(1))
886 3586176 : id2=MODULO(g1mg2(2),ngfft(2))
887 3586176 : id3=MODULO(g1mg2(3),ngfft(3))
888 3586176 : fft_idx= 1 + id1 + id2*ngfft(1) + id3*ngfft(1)*ngfft(2)
889 :
890 3586176 : end function gsph_gmg_fftidx
891 : !!***
892 :
893 : !----------------------------------------------------------------------
894 :
895 : !!****f* m_gsphere/merge_and_sort_kg
896 : !! NAME
897 : !! merge_and_sort_kg
898 : !!
899 : !! FUNCTION
900 : !! This routine merges a set of k-centered G-spheres of cutoff energy ecut and
901 : !! returns a Gamma-centered G-spheres. The elements in the final G-spheres are packed with increasing module.
902 : !!
903 : !! INPUTS
904 : !! nkpt=Number of k-points
905 : !! kptns(3,nkpt)=The k-points in reduced coordinates defining the k-centered G-spheres.
906 : !! ecut=Cutoff energy for the k-centered G-spheres.
907 : !! nsym2=Number of symmetry operations.
908 : !! pinv=-1 if time-reversal can be used, 1 otherwise
909 : !! symrel2(3,3,nsym2)=symmetry operations in real space.
910 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
911 : !! prtvol=Flag defining the verbosity level.
912 : !!
913 : !! SIDE EFFECTS
914 : !! gbig(:,:)
915 : !! in input : pointer to NULL
916 : !! in output: gbig(3,1:npw) contains the set of G-vectors ordered by shell obtained by
917 : !! merging the k-centered sphere.
918 : !! shlim_p(:)
919 : !! in input : pointer to NULL
920 : !! in output: shlim_p(nbase)=Cumulative number of G-vectors for each shell.
921 : !! where nbase is the number of irreducible G"s found.
922 : !!
923 : !! SOURCE
924 :
925 469 : subroutine merge_and_sort_kg(nkpt,kptns,ecut,nsym2,pinv,symrel2,gprimd,gbig,prtvol,shlim_p)
926 :
927 : !Arguments ------------------------------------
928 : !scalars
929 : integer,intent(in) :: nkpt,nsym2,pinv,prtvol
930 : real(dp),intent(in) :: ecut
931 : !arrays
932 : integer,intent(in) :: symrel2(3,3,nsym2)
933 : real(dp),intent(in) :: kptns(3,nkpt),gprimd(3,3)
934 : integer,pointer :: gbig(:,:)
935 : integer,optional,pointer :: shlim_p(:)
936 :
937 : !Local variables-------------------------------
938 : !scalars
939 : integer,parameter :: mkmem_=1
940 : integer :: ikg,ig,ikpt,nbase,sizepw,in,maxpw,is,iinv,ish,ilim,mpw
941 : integer :: exchn2n3d,istwf_k,onpw_k,ierr,npw_k,ii,isym,sizeold
942 : logical :: found
943 : character(len=500) :: msg
944 469 : type(MPI_type) :: MPI_enreg_seq
945 : !arrays
946 938 : integer :: gcur(3),geq(3),dum_kg(3,0),symrec2t(3,3,nsym2)
947 469 : integer,allocatable :: gbase(:,:),gbasek(:,:,:)
948 469 : integer,allocatable :: gcurr(:,:),gshell(:,:),insort(:),gtmp(:,:)
949 469 : integer,allocatable :: nbasek(:),nshell(:),shlim(:), npwarr(:)
950 : real(dp) :: kpoint(3),gmet(3,3)
951 469 : real(dp),allocatable :: cnorm(:),cnormk(:,:),ctmp(:)
952 : ! *********************************************************************
953 :
954 : ! Fake MPI_type for the sequential part.
955 : ! This routine should not be parallelized as communicating gbig and other
956 : ! tables takes more time than recalculating them in sequential.
957 469 : call initmpi_seq(MPI_enreg_seq)
958 :
959 : !Compute reciprocal space metrics
960 1876 : do ii=1,3
961 : gmet(ii,:)=gprimd(1,ii)*gprimd(1,:)+&
962 : & gprimd(2,ii)*gprimd(2,:)+&
963 6097 : & gprimd(3,ii)*gprimd(3,:)
964 : end do
965 :
966 : ! * Here we use TRANSPOSE(symrel2) instead of the more intuitive symrel2^{-1t} for historical reasons
967 : ! It does not affect the results since in the code below we only check the module of G
968 19207 : do isym=1,nsym2
969 244063 : symrec2t(:,:,isym)=TRANSPOSE(symrel2(:,:,isym))
970 : end do
971 : !
972 : ! ==============================================
973 : ! ==== Find irreducible G-vectors at each k ====
974 : ! ==============================================
975 :
976 1407 : ABI_MALLOC(npwarr,(nkpt))
977 469 : exchn2n3d=0; ikg=0
978 2722 : do ikpt=1,nkpt
979 9012 : kpoint=kptns(:,ikpt); istwf_k=1
980 2722 : call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,dum_kg,kpoint,0,MPI_enreg_seq,0,npwarr(ikpt))
981 : end do
982 2722 : mpw = MAXVAL(npwarr)
983 :
984 938 : ABI_MALLOC(nbasek,(nkpt))
985 1876 : ABI_MALLOC(gbasek,(3,mpw,nkpt))
986 1876 : ABI_MALLOC(cnormk,(mpw,nkpt))
987 2722 : nbasek=0 ! # of irreducible G at each k.
988 904022 : cnormk=zero ! Norm of each irreducible G.
989 3607922 : gbasek=0 ! The set of irreducible G"s at each k.
990 :
991 2722 : do ikpt=1,nkpt
992 :
993 9012 : kpoint = kptns(:,ikpt)
994 2253 : npw_k = npwarr(ikpt)
995 :
996 2253 : exchn2n3d=0; ikg=0; istwf_k=1
997 6759 : ABI_MALLOC(gcurr,(3,npw_k))
998 2253 : call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,gcurr,kpoint,mkmem_,MPI_enreg_seq,npw_k,onpw_k)
999 :
1000 9012 : if (ANY(gcurr(:,1)/=0)) then
1001 0 : ABI_BUG("gcurr(:,1)/=0")
1002 : end if
1003 : !
1004 : ! * Search for the G"s generating the others by symmetry.
1005 : ! NB: Here we use symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1006 2253 : call get_irredg(npw_k,nsym2,pinv,gprimd,symrec2t,gcurr,nbasek(ikpt),gbasek(:,:,ikpt),cnormk(:,ikpt))
1007 :
1008 2722 : ABI_FREE(gcurr)
1009 : end do
1010 : !
1011 : ! === Reduce info over k-points ===
1012 : ! * Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1013 469 : sizepw=2*mpw
1014 1407 : ABI_MALLOC(gbase,(3,sizepw))
1015 1407 : ABI_MALLOC(cnorm,(sizepw))
1016 : nbase=0 ! # of irred G found.
1017 :
1018 469 : call merge_kgirr(nsym2,pinv,nkpt,mpw,sizepw,symrec2t,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
1019 469 : if (ierr/=0) then
1020 0 : ABI_ERROR('merge_kgirr returned a non-zero status error')
1021 : end if
1022 :
1023 469 : ABI_FREE(nbasek)
1024 469 : ABI_FREE(cnormk)
1025 469 : ABI_FREE(gbasek)
1026 : !
1027 : !=== Reorder base G-vectors in order of increasing module ===
1028 : !
1029 : !Generate all shells of G-vectors: star of a g==set of all symmetrics of this g
1030 1407 : ABI_MALLOC(gshell,(3,2*nsym2))
1031 1407 : ABI_MALLOC(shlim,(nbase))
1032 :
1033 938 : ABI_MALLOC(gbig,(3,sizepw))
1034 : !
1035 : !TODO
1036 : #if 0
1037 : !* Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1038 : call getfullg(nbase,nsym2,pinv,sizepw,gbase,symrec2t,cnorm,maxpw,gbig,shlim,ierr)
1039 : if (ierr/0) RETURN
1040 :
1041 : #else
1042 938 : ABI_MALLOC(insort,(nbase))
1043 938 : ABI_MALLOC(nshell,(nbase))
1044 37400 : do in=1,nbase
1045 37400 : insort(in)=in
1046 : end do
1047 469 : call sort_dp(nbase,cnorm,insort,tol14)
1048 : !
1049 : !Loop over all different modules of g''s (=shells):
1050 469 : maxpw=0
1051 37400 : do in=1,nbase
1052 36931 : nshell(in)=0
1053 147724 : gcur(:)=gbase(:,insort(in))
1054 :
1055 853453 : do is=1,nsym2 ! Loop over all symmetries:
1056 1669975 : do iinv=pinv,1,2
1057 3266088 : geq(:)=iinv*(symrel2(1,:,is)*gcur(1)+symrel2(2,:,is)*gcur(2)+symrel2(3,:,is)*gcur(3))
1058 :
1059 : found=.FALSE.; ish=1
1060 7050483 : do while ((.not.found) .and. (ish<=nshell(in))) ! Search for symmetric of g and eventually add it:
1061 8227704 : found=ALL(geq(:)==gshell(:,ish))
1062 6730442 : ish=ish+1
1063 : end do
1064 1633044 : if (.not.found) then
1065 496481 : nshell(in)=nshell(in)+1
1066 1985924 : gshell(:,nshell(in))=geq(:)
1067 : end if
1068 : end do
1069 : end do
1070 :
1071 36931 : if ((maxpw+nshell(in)) > sizepw) then
1072 : ! We need to increase the size of the gbase, gbig and cnorm arrays while still keeping their content.
1073 : ! This is done using two temporary arrays gtmp and ctmp
1074 0 : ABI_WARNING("Had to reallocate gbase, gbig, cnorm. Perhaps geometry too inaccurate. Possible fix: correct your input file.")
1075 0 : ABI_MALLOC(ctmp,(sizepw))
1076 0 : ABI_MALLOC(gtmp,(3,sizepw))
1077 0 : sizeold=sizepw
1078 0 : sizepw=maxpw+nshell(in)
1079 :
1080 0 : ctmp(:)=cnorm(:)
1081 0 : gtmp(:,:)=gbase(:,:)
1082 :
1083 0 : ABI_FREE(cnorm)
1084 0 : ABI_MALLOC(cnorm,(sizepw))
1085 0 : cnorm(1:sizeold)=ctmp(1:sizeold)
1086 0 : cnorm(sizeold+1:sizepw)=zero
1087 0 : ABI_FREE(ctmp)
1088 :
1089 : ! MG why this? gbase should not be changed!
1090 0 : ABI_FREE(gbase)
1091 0 : ABI_MALLOC(gbase,(3,sizepw))
1092 0 : gbase(:,:sizeold)=gtmp(:,:sizeold)
1093 0 : gbase(:,sizeold+1:sizepw)=0
1094 0 : gtmp(:,:)=gbig(:,:)
1095 :
1096 0 : ABI_FREE(gbig)
1097 0 : ABI_MALLOC(gbig,(3,sizepw))
1098 0 : gbig(:,:sizeold)=gtmp(:,:sizeold)
1099 0 : gbig(:,sizeold+1:sizepw)=0
1100 0 : ABI_FREE(gtmp)
1101 : end if
1102 : !
1103 : ! Store this shell of g''s in a big array of g (gbig):
1104 533412 : do ig=1,nshell(in)
1105 2022855 : gbig(:,ig+maxpw)=gshell(:,ig)
1106 : end do
1107 37400 : maxpw=maxpw+nshell(in)
1108 :
1109 : end do ! End loop over shells
1110 : !
1111 : ! * Compute shell limits
1112 469 : ilim=0
1113 37400 : do in=1,nbase
1114 36931 : ilim=ilim+nshell(in)
1115 37400 : shlim(in)=ilim
1116 : end do
1117 :
1118 469 : if (PRESENT(shlim_p)) then ! Return shlim_p
1119 726 : ABI_MALLOC(shlim_p,(nbase))
1120 20880 : shlim_p = shlim
1121 : end if
1122 :
1123 : ! Re-allocate gbig with correct sizes so that caller can inquire the size
1124 1407 : ABI_MALLOC(gtmp,(3,ilim))
1125 1986862 : gtmp = gbig(:,1:ilim)
1126 469 : ABI_FREE(gbig)
1127 938 : ABI_MALLOC(gbig,(3,ilim))
1128 1986393 : gbig=gtmp
1129 469 : ABI_FREE(gtmp)
1130 :
1131 469 : if (prtvol>10) then ! Print out shell limits
1132 : write(msg,'(3a)')&
1133 0 : & ' Shells found:',ch10,&
1134 0 : & ' number of shell number of G vectors cut-off energy [Ha} '
1135 0 : call wrtout(std_out,msg)
1136 0 : do in=1,nbase
1137 0 : write(msg,'(12x,i4,17x,i6,12x,f8.3)')in,shlim(in),2*pi**2*cnorm(in)
1138 0 : call wrtout(std_out,msg)
1139 : end do
1140 0 : call wrtout(std_out,ch10)
1141 : end if
1142 :
1143 469 : ABI_FREE(gshell)
1144 469 : ABI_FREE(insort)
1145 469 : ABI_FREE(nshell)
1146 : #endif
1147 :
1148 469 : call destroy_mpi_enreg(MPI_enreg_seq)
1149 469 : ABI_FREE(gbase)
1150 469 : ABI_FREE(shlim)
1151 469 : ABI_FREE(cnorm)
1152 469 : ABI_FREE(npwarr)
1153 :
1154 938 : end subroutine merge_and_sort_kg
1155 : !!***
1156 :
1157 : !----------------------------------------------------------------------
1158 :
1159 : !!****f* m_gsphere/getfullg
1160 : !! NAME
1161 : !! getfullg
1162 : !!
1163 : !! FUNCTION
1164 : !! Reconstruct a G-sphere starting from a set of irreducible lattice vectors
1165 : !!
1166 : !! INPUTS
1167 : !! pinv=-1 if time-reversal can be used, 1 otherwise
1168 : !! nsym=number of symmetry operations
1169 : !! sizepw=Max expected number of G vectors in the shere
1170 : !! symrec(3,3,nsym)=symmetry operation in reciprocal space
1171 : !! nbase=number of irreducible G vectors
1172 : !! gbase(3,nbase)=irreducible G-vectors
1173 : !! cnorm(nbase)=norm of the irreducible G vectors (supposed not yet sorted)
1174 : !!
1175 : !! OUTPUT
1176 : !! maxpw=Number of G vectors found
1177 : !! gbig(3,sizepw)=G vectors in the sphere packed in the first maxpw columns
1178 : !! shlim(nbase)=number of G vectors within each shell
1179 : !! ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw
1180 : !!
1181 : !! SIDE EFFECTS
1182 : !!
1183 : !! NOTES
1184 : !! cnorm is a bit redundant since it can be calculated from gbase. However this procedure
1185 : !! is called by outkss in which cnorm is already calculated and we dont want to do it twice
1186 : !!
1187 : !! SOURCE
1188 :
1189 : subroutine getfullg(nbase,nsym,pinv,sizepw,gbase,symrec,cnorm,maxpw,gbig,shlim,ierr)
1190 :
1191 : !Arguments ------------------------------------
1192 : !scalars
1193 : integer,intent(in) :: nbase,nsym,pinv,sizepw
1194 : integer,intent(out) :: ierr,maxpw
1195 : !arrays
1196 : integer,intent(in) :: gbase(3,nbase),symrec(3,3,nsym)
1197 : integer,intent(out) :: gbig(3,sizepw),shlim(nbase)
1198 : real(dp),intent(inout) :: cnorm(nbase) !sort_dp can change cnorm
1199 :
1200 : !Local variables-------------------------------
1201 : !scalars
1202 : integer :: ibase,ig,ilim,ish,isym,itim
1203 : logical :: found
1204 : character(len=500) :: msg
1205 : !arrays
1206 : integer :: gcur(3),geq(3)
1207 : integer,allocatable :: gshell(:,:),insort(:),nshell(:)
1208 : ! *************************************************************************
1209 :
1210 : if (pinv/=1.and.pinv/=-1) then
1211 : write(msg,'(a,i6)')&
1212 : & ' The argument pinv should be -1 or 1, however, pinv =',pinv
1213 : ABI_BUG(msg)
1214 : end if
1215 : !
1216 : ! === Reorder base g-vectors in order of increasing module ===
1217 : ABI_MALLOC(insort,(nbase))
1218 : do ibase=1,nbase
1219 : insort(ibase)=ibase
1220 : end do
1221 : call sort_dp(nbase,cnorm,insort,tol14)
1222 : !
1223 : ! === Generate all stars of G-vectors ===
1224 : ! Star of G is the set of all symmetrical images of the vector
1225 : ! gshell contains the symmetrical G at fixed gbase. No need to add an additional dimension
1226 : ! or initialize to zero the array inside the loop over nbase as we loop over (ish<=nshell(ibase))
1227 : ABI_MALLOC(nshell,(nbase))
1228 : ABI_MALLOC(gshell,(3,2*nsym))
1229 : !
1230 : ! === Start with zero number of G vectors found ===
1231 : maxpw=0 ; ierr=0
1232 : do ibase=1,nbase
1233 : !
1234 : ! === Loop over all different modules of G ===
1235 : ! * Start with zero G vectors found in this star
1236 : nshell(ibase)=0
1237 : gcur(:)=gbase(:,insort(ibase))
1238 : !
1239 : ! === Loop over symmetries ===
1240 : do isym=1,nsym
1241 : do itim=pinv,1,2
1242 : geq(:)=itim*MATMUL(symrec(:,:,isym),gcur)
1243 : !
1244 : ! * Search for symmetric of g and eventually add it:
1245 : found=.FALSE. ; ish=1
1246 : do while ((.not.found).and. (ish<=nshell(ibase)))
1247 : found=ALL(geq(:)==gshell(:,ish))
1248 : ish=ish+1
1249 : end do
1250 : if (.not.found) then
1251 : nshell(ibase)=nshell(ibase)+1
1252 : gshell(:,nshell(ibase))=geq(:)
1253 : end if
1254 : end do
1255 : end do
1256 : !
1257 : ! * Was sizepw large enough?
1258 : if ((maxpw+nshell(ibase))>sizepw) then
1259 : write(msg,'(a,i6,2a)')&
1260 : & ' Number of G in sphere exceeds maximum allowed value =',sizepw,ch10,&
1261 : & ' check the value of sizepw in calling routine '
1262 : ABI_WARNING(msg)
1263 : ierr=1; RETURN
1264 : end if
1265 : !
1266 : ! === Store this shell of Gs in a big array (gbig) ===
1267 : do ig=1,nshell(ibase)
1268 : gbig(:,ig+maxpw)=gshell(:,ig)
1269 : end do
1270 : maxpw=maxpw+nshell(ibase)
1271 : end do ! ibase
1272 : !
1273 : ! === Compute number of G"s within each shell ===
1274 : ilim=0
1275 : do ibase=1,nbase
1276 : ilim=ilim+nshell(ibase)
1277 : shlim(ibase)=ilim
1278 : end do
1279 : !
1280 : ! === Print out shell limits ===
1281 : write(msg,'(3a)')&
1282 : & ' Shells found:',ch10,&
1283 : & ' number of shell number of G vectors cut-off energy [Ha] '
1284 : call wrtout(std_out,msg)
1285 :
1286 : do ibase=1,nbase
1287 : write(msg,'(12x,i4,17x,i6,12x,f8.3)')ibase,shlim(ibase),two*pi**2*cnorm(ibase)
1288 : call wrtout(std_out,msg)
1289 : end do
1290 : write(msg,'(a)')ch10
1291 : call wrtout(std_out,msg)
1292 : ABI_FREE(gshell)
1293 : ABI_FREE(insort)
1294 : ABI_FREE(nshell)
1295 :
1296 : end subroutine getfullg
1297 : !!***
1298 :
1299 : !----------------------------------------------------------------------
1300 :
1301 : !!****f* m_gsphere/get_irredg
1302 : !! NAME
1303 : !! get_irredg
1304 : !!
1305 : !! FUNCTION
1306 : !! Given a set of reciprocal lattice vectors, find the set of G"s generating the others by symmetry.
1307 : !!
1308 : !! INPUTS
1309 : !! nsym=number of symmetry operations
1310 : !! pinv=-1 if time-reversal can be used, 1 otherwise
1311 : !! npw_k=number of G vectors (for this k-point, as the set of G is k-centered)
1312 : !! gcurr(3,npw_k)=the list of G vectors
1313 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
1314 : !! symrec(3,3,nsym)=symmetry operations in terms of reciprocal space primitive translations.
1315 : !!
1316 : !! OUTPUT
1317 : !! nbasek=number of irreducible G vectors found
1318 : !! cnormk(npw_k)=first nbasek elements are the norm of each irreducible G-vector
1319 : !! gbasek(3,npw_k)=first nbasek elements are the irreducible G vectors
1320 : !!
1321 : !! NOTES
1322 : !! The search can be optimized by looping over shells. See m_skw for a faster algo
1323 : !!
1324 : !! SOURCE
1325 :
1326 3526 : subroutine get_irredg(npw_k,nsym,pinv,gprimd,symrec,gcurr,nbasek,gbasek,cnormk)
1327 :
1328 : !Arguments ------------------------------------
1329 : !scalars
1330 : integer,intent(in) :: npw_k,nsym,pinv
1331 : integer,intent(out) :: nbasek
1332 : !arrays
1333 : integer,intent(in) :: gcurr(3,npw_k),symrec(3,3,nsym)
1334 : integer,intent(out) :: gbasek(3,npw_k)
1335 : real(dp),intent(in) :: gprimd(3,3)
1336 : real(dp),intent(out) :: cnormk(npw_k)
1337 :
1338 : !Local variables-------------------------------
1339 : !scalars
1340 : integer :: ig,irr,isym,jj
1341 : real(dp) :: eps,norm
1342 : logical :: found
1343 : !arrays
1344 : integer :: gbas(3),gcur(3),geq(3)
1345 : real(dp) :: gcar(3)
1346 : ! *************************************************************************
1347 :
1348 : DBG_ENTER("COLL")
1349 :
1350 3526 : if (pinv/=1.and.pinv/=-1) then
1351 0 : ABI_BUG(sjoin('pinv should be -1 or 1, however, pinv =', itoa(pinv)))
1352 : end if
1353 :
1354 : ! Zero irred G vectors found, zeroing output arrays.
1355 4569461 : nbasek = 0; cnormk(:) = zero; gbasek(:,:) = 0
1356 :
1357 916713 : do ig=1,npw_k
1358 3652748 : gcur(:) = gcurr(:,ig); norm = zero
1359 3652748 : do jj=1,3
1360 2739561 : gcar(jj)=gcur(1)*gprimd(jj,1)+gcur(2)*gprimd(jj,2)+gcur(3)*gprimd(jj,3)
1361 3652748 : norm=norm+gcar(jj)**2
1362 : end do
1363 913187 : eps = tol8 * norm; found = .False.; irr = 1
1364 113280552 : do while (.not.found .and. irr <= nbasek) ! This loop can be optimized by looping inside the shell.
1365 112367365 : if (abs(norm - cnormk(irr)) <= eps) then
1366 7264036 : gbas(:) = gbasek(:,irr); isym = 1
1367 31324101 : do while (.not.found .and. isym <= nsym)
1368 383605196 : geq(:) = matmul(symrec(:,:,isym),gcur)
1369 34650661 : found = all(geq(:) == gbas(:))
1370 29508092 : if (pinv == -1) found = (found .or. all(geq == -gbas)) ! For time-reversal
1371 31324101 : isym = isym + 1
1372 : end do
1373 : end if
1374 112445004 : irr = irr + 1
1375 : end do
1376 916713 : if (.not. found) then
1377 310556 : nbasek = nbasek + 1; cnormk(nbasek) = norm; gbasek(:,nbasek) = gcur(:)
1378 : end if
1379 : end do
1380 :
1381 : DBG_EXIT("COLL")
1382 :
1383 3526 : end subroutine get_irredg
1384 : !!***
1385 :
1386 : !----------------------------------------------------------------------
1387 :
1388 : !!****f* m_gsphere/merge_kgirr
1389 : !! NAME
1390 : !! merge_kgirr
1391 : !!
1392 : !! FUNCTION
1393 : !! Given a list of irreducible reciprocal vectors associated to different k-centered spheres,
1394 : !! this subroutine finds the minimal set of G vectors needed to reconstruct the union of the spheres
1395 : !! through symmetry operations.
1396 : !!
1397 : !! INPUTS
1398 : !! nsym=number of symmetry operations
1399 : !! pinv=-1 if time-reversal can be used, 0 otherwise
1400 : !! nkpt=number of k-points for k-centered spheres
1401 : !! mpw=Max number of G vectors for each k-point
1402 : !! sizepw=Max expected number of G vectors found
1403 : !! symrec(3,3,nsym)=symmetries in reciprocal space given in reduced coordinates
1404 : !! nbasek(nkpt)=number of irred G for each k-point
1405 : !! cnormk(mpw,nkpt)=the norm of each k-centered G (only 1:nbase(ik)) is used
1406 : !! gbasek(3,mpw,nkpt)
1407 : !!
1408 : !! OUTPUT
1409 : !! nbase=number of irreducible G needed to reconstruct the initial set of spheres
1410 : !! gbase(3,sizepw)=irreducible G found in reciprocal coordinates
1411 : !! cnorm(sizepw)=Norm of each irred G vector
1412 : !! ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw
1413 : !!
1414 : !! SOURCE
1415 :
1416 469 : subroutine merge_kgirr(nsym,pinv,nkpt,mpw,sizepw,symrec,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
1417 :
1418 : !Arguments ------------------------------------
1419 : !scalars
1420 : integer,intent(in) :: mpw,nkpt,nsym,pinv,sizepw
1421 : integer,intent(out) :: ierr,nbase
1422 : !arrays
1423 : integer,intent(in) :: gbasek(3,mpw,nkpt),nbasek(nkpt),symrec(3,3,nsym)
1424 : integer,intent(inout) :: gbase(3,sizepw) !vz_i
1425 : real(dp),intent(in) :: cnormk(mpw,nkpt)
1426 : real(dp),intent(inout) :: cnorm(sizepw) !vz_i
1427 :
1428 : !Local variables-------------------------------
1429 : !scalars
1430 : integer :: ikpt,inb,irgk,isym
1431 : real(dp) :: eps,norm
1432 : logical :: found
1433 : character(len=500) :: msg
1434 : !arrays
1435 : integer :: gbas(3),gcur(3),geq(3)
1436 : ! *************************************************************************
1437 :
1438 : DBG_ENTER("COLL")
1439 :
1440 469 : if (pinv/=1.and.pinv/=-1) then
1441 0 : write(msg,'(a,i6)')' The argument pinv should be -1 or 1, however, pinv =',pinv
1442 0 : ABI_BUG(msg)
1443 : end if
1444 : !
1445 : ! === Start with zero number of G found ===
1446 469 : nbase=0 ; ierr=0
1447 2722 : do ikpt=1,nkpt
1448 78198 : do irgk=1,nbasek(ikpt)
1449 301904 : gcur(:)=gbasek(:,irgk,ikpt)
1450 75476 : norm=cnormk(irgk,ikpt) ; eps=tol8*norm
1451 75476 : found=.FALSE. ; inb=1
1452 9601384 : do while ((.not.found).and.(inb<=nbase))
1453 9525908 : if (ABS(norm-cnorm(inb))<=eps) then
1454 510904 : gbas(:)=gbase(:,inb)
1455 : isym=1
1456 1615525 : do while ((.not.found).and.(isym<=nsym))
1457 19341387 : geq(:)=MATMUL(symrec(:,:,isym),gcur)
1458 1720250 : found=ALL(geq(:)==gbas(:))
1459 1487799 : if (pinv==-1) found= (found.or.ALL(geq(:)==-gbas(:)) ) ! For time-reversal
1460 1615525 : isym=isym+1
1461 : end do
1462 : end if
1463 9562839 : inb=inb+1
1464 : end do
1465 77729 : if (.not.found) then
1466 : ! === Add to the list ===
1467 36931 : nbase=nbase+1
1468 36931 : if (nbase>sizepw) then
1469 : write(msg,'(2(a,i5),a)')&
1470 0 : & ' nbase (',nbase,') became greater than sizepw = ',sizepw,' returning ierr=1 '
1471 0 : ABI_WARNING(msg)
1472 0 : ierr=1; RETURN
1473 : end if
1474 36931 : cnorm(nbase)=cnormk(irgk,ikpt)
1475 147724 : gbase(:,nbase)=gcur(:)
1476 : end if
1477 : end do
1478 : end do
1479 :
1480 : DBG_EXIT("COLL")
1481 :
1482 : end subroutine merge_kgirr
1483 : !!***
1484 :
1485 : !----------------------------------------------------------------------
1486 :
1487 : !!****f* m_gpshere/setshells
1488 : !! NAME
1489 : !! setshells
1490 : !!
1491 : !! FUNCTION
1492 : !! Set consistently the number of shells, the number of plane-waves, and the energy cut-off
1493 : !!
1494 : !! INPUTS
1495 : !! nsym=number of symmetry operations
1496 : !! gmet(3,3)=metric tensor in reciprocal space
1497 : !! gprimd(3,3)=dimensional primitive vectors in reciprocal space
1498 : !! symrel(3,3,nsym)=symmetry operations in real space
1499 : !! tag=suffix to account for the different possibilities for these variables (npw, ecut or nsh ..)
1500 : !! ucvol=unit cell volume
1501 : !!
1502 : !! OUTPUT
1503 : !! (see side effects)
1504 : !!
1505 : !! SIDE EFFECTS
1506 : !! ecut,npw,nsh=one of them is an input, the two others are output
1507 : !! ecut=cut-off energy for plane wave basis sphere (Ha)
1508 : !! npw=number of plane waves
1509 : !! nsh=number of shells
1510 : !!
1511 : !! SOURCE
1512 :
1513 1396 : subroutine setshells(ecut,npw,nsh,nsym,gmet,gprimd,symrel,tag,ucvol)
1514 :
1515 : !Arguments ------------------------------------
1516 : !scalars
1517 : integer,intent(in) :: nsym
1518 : integer,intent(inout) :: npw,nsh
1519 : real(dp),intent(in) :: ucvol
1520 : real(dp),intent(inout) :: ecut
1521 : character(len=*),intent(in) :: tag
1522 : !arrays
1523 : integer,intent(in) :: symrel(3,3,nsym)
1524 : real(dp),intent(in) :: gmet(3,3),gprimd(3,3)
1525 :
1526 : !Local variables-------------------------------
1527 : !scalars
1528 : integer :: exchn2n3d,ifound,ig,ii,ish,isym,npw_found,npwave
1529 : integer :: npwwrk,nsh_found,pad=50
1530 : real(dp) :: ecut_found,ecut_trial,eps,scale=1.3_dp
1531 : logical :: found
1532 : character(len=500) :: msg
1533 1396 : type(MPI_type) :: MPI_enreg_seq
1534 : !arrays
1535 : integer :: geq(3)
1536 1396 : integer,allocatable :: gvec(:,:),gvec_sh(:,:),insort(:),npw_sh(:)
1537 : real(dp) :: gctr(3)
1538 1396 : real(dp),allocatable :: gnorm(:),gnorm_sh(:)
1539 :
1540 : !******************************************************************
1541 :
1542 : ! Check coherence of input variables ecut, npw, and nsh.
1543 : ! 1-> one at least should be non-null
1544 1396 : if (npw==0.and.nsh==0.and.ecut<=tol6) then
1545 : write(msg,'(8a)')&
1546 176 : 'One of the three variables ecut',TRIM(tag),', npw',TRIM(tag),', or nsh',TRIM(tag),ch10,&
1547 352 : 'must be non-null. Returning.'
1548 176 : ABI_COMMENT(msg)
1549 176 : RETURN
1550 : end if
1551 : ! 2-> one and only one should be non-null
1552 1220 : if (npw/=0.and.nsh/=0) then
1553 : write(msg,'(6a)')&
1554 0 : 'Only one of the two variables npw',TRIM(tag),' and nsh',TRIM(tag),ch10,&
1555 0 : 'can be non-null. Modify the value of one of these in input file.'
1556 0 : ABI_ERROR(msg)
1557 : end if
1558 1220 : if (ecut>tol6.and.npw/=0) then
1559 : write(msg,'(6a)')&
1560 0 : 'Only one of the two variables ecut',TRIM(tag),' and npw',TRIM(tag),ch10,&
1561 0 : 'can be non-null. Modify the value of one of these in input file.'
1562 0 : ABI_ERROR(msg)
1563 : end if
1564 1220 : if (ecut>tol6.and.nsh/=0) then
1565 : write(msg,'(6a)')&
1566 0 : 'Only one of the two variables ecut',TRIM(tag),' and nsh',TRIM(tag),ch10,&
1567 0 : 'can be non-null Action : modify the value of one of these in input file.'
1568 0 : ABI_ERROR(msg)
1569 : end if
1570 :
1571 : ! Calculate an upper bound for npw.
1572 : ! gctr is center of the g-vector sphere
1573 1220 : gctr(:)= [zero,zero,zero]
1574 1220 : if (ecut>tol6) then
1575 : ! The average number of plane-waves in the cutoff sphere is given by:
1576 : ! npwave = (2*ecut)**(3/2)*ucvol/(6*pi**2)
1577 : ! The upper bound is calculated as npwwrk=int(scale * npwave) + pad
1578 1092 : npwave=NINT(ucvol*(two*ecut)**1.5_dp/(six*pi**2))
1579 1092 : npwwrk=NINT(DBLE(npwave)*scale)+pad
1580 1092 : ecut_trial=ecut
1581 128 : else if (npw/=0) then
1582 : ! npw is given in the input
1583 128 : npwwrk=NINT(DBLE(npw)*scale)+pad
1584 128 : ecut_trial=(six*pi**2*npw/ucvol)**two_thirds/two
1585 : else
1586 : ! If nsh is given in the input
1587 0 : npwwrk=nsh*18+2*pad
1588 0 : ecut_trial=(six*pi**2*nsh*18/ucvol)**two_thirds/two
1589 : end if
1590 :
1591 1220 : call initmpi_seq(MPI_enreg_seq)
1592 :
1593 3660 : ABI_MALLOC(gvec,(3,npwwrk))
1594 2440 : ifound=0
1595 2440 : do while (ifound==0)
1596 : !write(msg,'(a,f8.2)')' setshells : ecut_trial = ',ecut_trial
1597 : !call wrtout(std_out,msg,'COLL')
1598 1220 : exchn2n3d=0 ! For the time being, no exchange of n2 and n3
1599 :
1600 1220 : call kpgsph(ecut_trial,exchn2n3d,gmet,0,1,1,gvec,gctr,1,MPI_enreg_seq,npwwrk,npw_found)
1601 :
1602 3660 : ABI_MALLOC(gnorm,(npw_found))
1603 3660 : ABI_MALLOC(insort,(npw_found))
1604 :
1605 359454 : do ig=1,npw_found
1606 358234 : insort(ig)=ig
1607 358234 : gnorm(ig)=zero
1608 1434156 : do ii=1,3
1609 : gnorm(ig)=gnorm(ig)+(gvec(1,ig)*gprimd(ii,1)+&
1610 : gvec(2,ig)*gprimd(ii,2)+&
1611 1432936 : gvec(3,ig)*gprimd(ii,3))**2
1612 : end do
1613 : end do
1614 1220 : call sort_dp(npw_found,gnorm,insort,tol14)
1615 :
1616 2440 : ABI_MALLOC(npw_sh,(npw_found))
1617 2440 : ABI_MALLOC(gnorm_sh,(npw_found))
1618 3660 : ABI_MALLOC(gvec_sh,(3,npw_found))
1619 359454 : npw_sh(:)=0
1620 359454 : gnorm_sh(:)=zero
1621 1434156 : gvec_sh(:,:)=0
1622 : ! Count the number of shells:
1623 : ! (search for the G-vectors generating the others by symmetry)
1624 1220 : nsh_found=0
1625 :
1626 359454 : do ig=1,npw_found
1627 358234 : eps=1.d-8*gnorm(ig)
1628 358234 : found=.FALSE.
1629 358234 : ish=1
1630 43087727 : do while ((.not.found).and.(ish<=nsh_found))
1631 42729493 : if (ABS(gnorm(ig)-gnorm_sh(ish))<=eps) then
1632 : isym=1
1633 11871425 : do while ((.not.found).and.(isym<=nsym))
1634 : geq(:)=(symrel(1,:,isym)*gvec(1,insort(ig))+&
1635 : symrel(2,:,isym)*gvec(2,insort(ig))+&
1636 44360616 : symrel(3,:,isym)*gvec(3,insort(ig)))
1637 :
1638 : found=((geq(1)==gvec_sh(1,ish)).and.&
1639 : (geq(2)==gvec_sh(2,ish)).and.&
1640 11090154 : (geq(3)==gvec_sh(3,ish)))
1641 11417526 : isym=isym+1
1642 : end do
1643 : end if
1644 42729493 : ish=ish+1
1645 : end do
1646 359454 : if (.not.found) then
1647 30862 : nsh_found=nsh_found+1
1648 30862 : gnorm_sh(nsh_found)=gnorm(ig)
1649 123448 : gvec_sh(:,nsh_found)=gvec(:,insort(ig))
1650 30862 : npw_sh(nsh_found)=1
1651 : else
1652 327372 : ish=ish-1
1653 327372 : npw_sh(ish)=npw_sh(ish)+1
1654 : end if
1655 : end do
1656 :
1657 1220 : ecut_found=two*pi**2*gnorm(npw_found)
1658 :
1659 1220 : if(ecut>tol6) then
1660 : ! ecut is given in the input
1661 : !if (ecut_found<ecut-0.1) then
1662 : ! write(msg,'(3a,e14.6,9a,e14.6,3a)')&
1663 : ! 'The value ecut',TRIM(tag),'=',ecut,' given in the input file leads to',ch10,&
1664 : ! 'the same values for nsh',TRIM(tag),' and npw',TRIM(tag),' as ecut',TRIM(tag),'=',ecut_found,ch10
1665 : ! ABI_COMMENT(msg)
1666 : !end if
1667 : ifound=1
1668 128 : else if (npw/=0) then
1669 : ! If npw is given in the input
1670 128 : if (npw_found==npw) then
1671 : ecut_found=two*pi**2*gnorm(npw_found)
1672 : ifound=1
1673 11 : else if (npw_found>npw) then
1674 11 : npw_found=0
1675 11 : nsh_found=0
1676 60 : do while (npw_found<npw)
1677 49 : nsh_found=nsh_found+1
1678 49 : npw_found=npw_found+npw_sh(nsh_found)
1679 : end do
1680 : ! check that the shell is closed
1681 11 : if(npw_found>npw) then
1682 : ! shell not closed
1683 0 : npw_found=npw_found-npw_sh(nsh_found)
1684 0 : nsh_found=nsh_found-1
1685 0 : do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
1686 0 : npw_found=npw_found-npw_sh(nsh_found)
1687 0 : nsh_found=nsh_found-1
1688 : end do
1689 : write(msg,'(3a,i6,5a,i6,3a)')&
1690 0 : 'The value npw',TRIM(tag),'=',npw,' given in the input file does not close the shell',ch10,&
1691 0 : 'The lower closed-shell is obtained for a value npw',TRIM(tag),'=',npw_found,ch10,&
1692 0 : 'This value will be adopted for the calculation.',ch10
1693 0 : ABI_WARNING(msg)
1694 : end if
1695 11 : ecut_found=two*pi**2*gnorm(npw_found)
1696 : ifound=1
1697 : end if
1698 0 : else if (nsh/=0) then
1699 : ! If nsh is given in the input
1700 0 : if (nsh_found==nsh) then
1701 : ecut_found=two*pi**2*gnorm(npw_found)
1702 : ifound=1
1703 0 : else if (nsh_found>nsh) then
1704 0 : npw_found=0
1705 0 : nsh_found=0
1706 0 : do ish=1,nsh
1707 0 : npw_found=npw_found+npw_sh(ish)
1708 0 : nsh_found=nsh_found+1
1709 : end do
1710 0 : if (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001) then
1711 0 : do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
1712 0 : nsh_found=nsh_found+1
1713 0 : npw_found=npw_found+npw_sh(nsh_found)
1714 : end do
1715 : write(msg,'(3a,i6,5a,i6,3a)')&
1716 0 : 'The value nsh',TRIM(tag),'=',nsh,' given in the input file corresponds to the same',ch10,&
1717 0 : 'cut-off energy as for closed-shell upto nsh',TRIM(tag),'=',nsh_found,ch10,&
1718 0 : 'This value will be adopted for the calculation.',ch10
1719 0 : ABI_WARNING(msg)
1720 : end if
1721 0 : ecut_found=two*pi**2*gnorm(npw_found)
1722 : ifound=1
1723 : end if
1724 : end if
1725 :
1726 1220 : if (ifound==0) then
1727 0 : ecut_trial=1.1*ecut_trial
1728 0 : ABI_FREE(gnorm)
1729 0 : ABI_FREE(gnorm_sh)
1730 0 : ABI_FREE(gvec_sh)
1731 0 : ABI_FREE(insort)
1732 0 : ABI_FREE(npw_sh)
1733 : else
1734 : ! ecut was not provided as an input, then set it now!
1735 1220 : if (ecut<tol6) then
1736 128 : ecut=ecut_found
1737 : end if
1738 1220 : npw=npw_found
1739 1220 : nsh=nsh_found
1740 : end if
1741 :
1742 : end do ! while(ifound==0)
1743 :
1744 1220 : call destroy_mpi_enreg(MPI_enreg_seq)
1745 :
1746 1220 : ABI_FREE(gnorm)
1747 1220 : ABI_FREE(gnorm_sh)
1748 1220 : ABI_FREE(gvec)
1749 1220 : ABI_FREE(gvec_sh)
1750 1220 : ABI_FREE(insort)
1751 1220 : ABI_FREE(npw_sh)
1752 :
1753 1396 : end subroutine setshells
1754 : !!***
1755 :
1756 : !----------------------------------------------------------------------
1757 :
1758 : !!****f* m_gsphere/kg_map
1759 : !! NAME
1760 : !! kg_map
1761 : !!
1762 : !! FUNCTION
1763 : !! Compute the mapping between two lists of g-vectors.
1764 : !!
1765 : !! INPUTS
1766 : !! npw1, kg1(3,npw1)=First list of G-vectors
1767 : !! npw2, kg2(3,npw2)=Second list of G-vectors
1768 : !!
1769 : !! OUTPUT
1770 : !! g2g1(npw2) = Mapping kg2 index --> kg1 index.
1771 : !! Set to 0 if kg2(:,ig) not in kg1
1772 : !! nmiss = Number of G-vectors in kg2 not found in kg1
1773 : !!
1774 : !! SOURCE
1775 :
1776 4252 : subroutine kg_map(npw1, kg1, npw2, kg2, g2g1, nmiss)
1777 :
1778 : !Arguments ------------------------------------
1779 : !scalars
1780 : integer,intent(in) :: npw1,npw2
1781 : integer,intent(out) :: nmiss
1782 : !arrays
1783 : integer,intent(in) :: kg1(3,npw1),kg2(3,npw2)
1784 : integer,intent(out) :: g2g1(npw2)
1785 :
1786 : !Local variables ------------------------------
1787 : !scalars
1788 : integer :: ii,ipw,i1,i2,i3,n1,n2,n3
1789 : !arrays
1790 : integer :: gmax(3),g1_max(3),g2_max(3)
1791 4252 : integer,allocatable :: iwork(:,:,:)
1792 : !************************************************************************
1793 :
1794 7443324 : g1_max = maxval(abs(kg1))
1795 7011176 : g2_max = maxval(abs(kg2))
1796 17008 : do ii=1,3
1797 17008 : gmax(ii) = max(g1_max(ii), g2_max(ii))
1798 : end do
1799 17008 : gmax = 2*gmax + 1
1800 4252 : n1 = gmax(1); n2 = gmax(2); n3 = gmax(3)
1801 :
1802 : !print *, "n1, n2, n3", n1, n2, n3; print *, "kg1:", kg1; print *, "kg2:", kg2
1803 21260 : ABI_MALLOC(iwork, (n1, n2, n3))
1804 :
1805 : ! Insert kg1 into work with extra 0 s around outside:
1806 6627552 : iwork = 0
1807 1859768 : do ipw=1,npw1
1808 1855516 : i1 = kg1(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
1809 1855516 : i2 = kg1(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
1810 1855516 : i3 = kg1(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
1811 1859768 : iwork(i1,i2,i3) = ipw
1812 : end do
1813 :
1814 1751731 : g2g1 = 0; nmiss = 0
1815 1751731 : do ipw=1,npw2
1816 1747479 : i1 = kg2(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
1817 1747479 : i2 = kg2(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
1818 1747479 : i3 = kg2(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
1819 : !#if defined FC_NVHPC
1820 : ! !if (n1 == -1) write(std_out, *)"NVHPC raises SIGSEGV"
1821 : ! print *, "ipw, i1, i2, i3, n1, n2, n3", ipw, i1, i2, i3, n1, n2, n3
1822 : !#endif
1823 1747479 : g2g1(ipw) = iwork(i1,i2,i3)
1824 1751731 : if (g2g1(ipw) == 0) nmiss = nmiss + 1
1825 : end do
1826 :
1827 4252 : ABI_FREE(iwork)
1828 :
1829 4252 : end subroutine kg_map
1830 : !!***
1831 :
1832 : !----------------------------------------------------------------------
1833 :
1834 : !!****f* m_gsphere/make_istwk_table
1835 : !! NAME
1836 : !! make_istwfk_table
1837 : !!
1838 : !! FUNCTION
1839 : !!
1840 : !! INPUTS
1841 : !! ng1,ng2,ng3
1842 : !!
1843 : !! OUTPUT
1844 : !!
1845 : !! NOTES
1846 : !! Useful relations:
1847 : !! u_k(G) = u_{k+G0}(G-G0); u_{-k}(G) = u_k(G)^*
1848 : !! and therefore:
1849 : !! u_{G0/2}(G) = u_{G0/2}(-G-G0)^*.
1850 : !!
1851 : !! SOURCE
1852 :
1853 0 : subroutine make_istwfk_table(istwf_k,ng1,ng2,ng3,ig1_inver,ig2_inver,ig3_inver)
1854 :
1855 : !Arguments ------------------------------------
1856 : !scalars
1857 : integer,intent(in) :: ng1,ng2,ng3,istwf_k
1858 : !arrays
1859 : integer,intent(out) :: ig1_inver(ng1),ig2_inver(ng2),ig3_inver(ng3)
1860 :
1861 : !Local variables ------------------------------
1862 : !scalars
1863 : integer :: i1,i2,i3
1864 : character(len=500) :: msg
1865 : !************************************************************************
1866 :
1867 : ! Initialize the inverse coordinates
1868 0 : select case (istwf_k)
1869 :
1870 : case (1)
1871 0 : ig1_inver(1)=1
1872 0 : do i1=2,ng1
1873 0 : ig1_inver(i1)=ng1+2-i1
1874 : end do
1875 0 : ig2_inver(1)=1
1876 0 : do i2=2,ng2
1877 0 : ig2_inver(i2)=ng2+2-i2
1878 : end do
1879 0 : ig3_inver(1)=1
1880 0 : do i3=2,ng3
1881 0 : ig3_inver(i3)=ng3+2-i3
1882 : end do
1883 :
1884 : case (2:8)
1885 0 : if (istwf_k==2 .or. istwf_k==4 .or. istwf_k==6 .or. istwf_k==8) then
1886 0 : ig1_inver(1)=1
1887 0 : do i1=2,ng1
1888 0 : ig1_inver(i1)=ng1+2-i1
1889 : end do
1890 : else
1891 0 : do i1=1,ng1
1892 0 : ig1_inver(i1)=ng1+1-i1
1893 : end do
1894 : end if
1895 0 : if (istwf_k>=2 .and. istwf_k<=5) then
1896 0 : ig2_inver(1)=1
1897 0 : do i2=2,ng2
1898 0 : ig2_inver(i2)=ng2+2-i2
1899 : end do
1900 : else
1901 0 : do i2=1,ng2
1902 0 : ig2_inver(i2)=ng2+1-i2
1903 : end do
1904 : end if
1905 0 : if (istwf_k==2 .or. istwf_k==3 .or. istwf_k==6 .or. istwf_k==7) then
1906 0 : ig3_inver(1)=1
1907 0 : do i3=2,ng3
1908 0 : ig3_inver(i3)=ng3+2-i3
1909 : end do
1910 : else
1911 0 : do i3=1,ng3
1912 0 : ig3_inver(i3)=ng3+1-i3
1913 : end do
1914 : end if
1915 :
1916 : case default
1917 0 : write(msg,'(a,i0)')" Wrong value for istwf_k: ",istwf_k
1918 0 : ABI_ERROR(msg)
1919 : end select
1920 :
1921 0 : end subroutine make_istwfk_table
1922 : !!***
1923 :
1924 : !----------------------------------------------------------------------
1925 :
1926 : !!****f* m_gsphere/table_gbig2kg
1927 : !! NAME
1928 : !! table_gbig2kg
1929 : !!
1930 : !! FUNCTION
1931 : !! Associate the kg_k set of g-vectors with the big array of gbig
1932 : !! The array gbig(3,maxpw) contains all g-vectors used for all k-points, in order of
1933 : !! increasing shells. For a each k-point, the wave-functions are defined only on a particular set
1934 : !! of g-vectors kg_k (included in gbig). This set is defined by array gamma2k:
1935 : !! The array gamma2k(ig=1,maxpw) translates the index of the gbig (from 1 to maxpw) into the corresponding
1936 : !! index in array kg_k. If gbig(ig) does not exist in kg_k, gamma2k(ig) contains npw_k+1.
1937 : !!
1938 : !! INPUTS
1939 : !! npw_k=Number of planewaves in the k-centered basis set
1940 : !! kg_k(3,npw_k)=The k-centered basis set
1941 : !! maxpw=Number of G in gbig
1942 : !! gbig(3,maxpw)=The union of the G-spheres at different k-points.
1943 : !!
1944 : !! OUTPUT
1945 : !! ierr=Status error. It gives the number of G of kg_k not contained in gbig.
1946 : !! gamma2k(maxpw)=Mapping gbig -> kg_k
1947 : !!
1948 : !! SOURCE
1949 :
1950 31 : pure subroutine table_gbig2kg(npw_k,kg_k,maxpw,gbig,gamma2k,ierr)
1951 :
1952 : !Arguments ------------------------------------
1953 : !scalars
1954 : integer,intent(in) :: npw_k,maxpw
1955 : integer,intent(out) :: ierr
1956 : !arrays
1957 : integer,intent(in) :: kg_k(3,npw_k)
1958 : integer,intent(in) :: gbig(3,maxpw)
1959 : integer,intent(out) :: gamma2k(maxpw)
1960 :
1961 : !Local variables-------------------------------
1962 : !scalars
1963 : integer :: ig,igp
1964 : logical :: found
1965 : !arrays
1966 : integer :: gcur(3)
1967 : ! *********************************************************************
1968 :
1969 31 : ierr=0
1970 30608 : gamma2k(:)=npw_k+1 ! Initialize array gamma2k
1971 :
1972 21877 : do ig=1,npw_k ! Loop over g-vectors, for this k point.
1973 87384 : gcur(:)=kg_k(:,ig)
1974 : igp=0; found=.FALSE.
1975 11381569 : do while ((.not.found) .and. igp<maxpw) ! Search selected vector in array gbig: TODO this part can be optimized
1976 11359723 : igp=igp+1
1977 12455395 : found=ALL(gcur(:)==gbig(:,igp))
1978 : end do
1979 21877 : if (found) then ! Store it if found:
1980 21846 : gamma2k(igp)=ig
1981 : else
1982 0 : ierr=ierr+1
1983 : end if
1984 : end do
1985 :
1986 31 : end subroutine table_gbig2kg
1987 : !!***
1988 :
1989 : !----------------------------------------------------------------------
1990 :
1991 : !!****f* m_gsphere/gsph_extend
1992 : !! NAME
1993 : !! gsph_extend
1994 : !!
1995 : !! FUNCTION
1996 : !! Construct a new gsphere_t with a larger cutoff energy
1997 : !! while preserving the ordering of the first G-vectors stored in in_Gsph
1998 : !!
1999 : !! INPUTS
2000 : !!
2001 : !! OUTPUT
2002 : !!
2003 : !! SOURCE
2004 :
2005 36 : subroutine gsph_extend(in_Gsph, Cryst, new_ecut, new_Gsph)
2006 :
2007 : !Arguments ------------------------------------
2008 : !scalars
2009 : class(gsphere_t),intent(in) :: in_Gsph
2010 : type(crystal_t),intent(in) :: Cryst
2011 : real(dp),intent(in) :: new_ecut
2012 : class(gsphere_t),intent(out) :: new_Gsph
2013 :
2014 : !Local variables-------------------------------
2015 : !scalars
2016 : integer :: new_ng,in_ng,ig,ierr,sh
2017 : !arrays
2018 36 : integer,allocatable :: new_gvec(:,:)
2019 : ! *********************************************************************
2020 :
2021 36 : call new_Gsph%init(Cryst, 0, ecut=new_ecut)
2022 :
2023 36 : if (new_Gsph%ng > in_Gsph%ng) then
2024 : ! new_gpsh larger than in_gsph
2025 34 : new_ng = new_Gsph%ng
2026 34 : in_ng = in_Gsph%ng
2027 :
2028 34 : ierr = 0
2029 1800 : do ig=1,in_ng
2030 7098 : if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
2031 0 : ierr = ierr + 1
2032 0 : write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
2033 : end if
2034 : end do
2035 :
2036 34 : if (ierr == 0) RETURN
2037 :
2038 0 : ierr = 0
2039 0 : do sh=1,in_Gsph%nsh
2040 0 : if (new_Gsph%shlim(sh) /= in_Gsph%shlim(sh) .or. &
2041 0 : ABS(new_Gsph%shlen(sh)-in_Gsph%shlen(sh)) > tol12 ) then
2042 0 : ierr = ierr + 1
2043 0 : write(std_out,*)"new_shlim, in_shlim",sh,new_Gsph%shlim(sh),in_Gsph%shlim(sh)
2044 0 : write(std_out,*)"new_shlen, in_shlen",sh,new_Gsph%shlen(sh),in_Gsph%shlen(sh)
2045 : end if
2046 : end do
2047 0 : ABI_CHECK(ierr == 0,"Wrong shells")
2048 :
2049 0 : ABI_MALLOC(new_gvec,(3, new_ng))
2050 0 : new_gvec = new_Gsph%gvec
2051 0 : new_gvec(:,1:in_ng) = in_Gsph%gvec
2052 :
2053 0 : call new_Gsph%free()
2054 0 : call new_Gsph%init(Cryst, new_ng, gvec=new_gvec)
2055 0 : ABI_FREE(new_gvec)
2056 :
2057 : else
2058 : ! new_gpsh smaller/equal than in_gsph
2059 2 : ierr = 0
2060 132 : do ig=1,MIN(new_Gsph%ng,in_Gsph%ng)
2061 522 : if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
2062 0 : ierr = ierr + 1
2063 0 : write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
2064 : end if
2065 : end do
2066 2 : ABI_CHECK(ierr==0,"Fatal error")
2067 : end if
2068 :
2069 : end subroutine gsph_extend
2070 : !!***
2071 :
2072 : !----------------------------------------------------------------------
2073 :
2074 : !!****f* m_gsphere/getkpgnorm
2075 : !! NAME
2076 : !! getkpgnorm
2077 : !!
2078 : !! FUNCTION
2079 : !! compute the norms of the k+G vectors
2080 : !!
2081 : !! INPUTS
2082 : !! gprimd(3,3)=metric tensor
2083 : !! kg_k(3,npw_k)= G vectors, in reduced coordinates
2084 : !! kpt(3)=k vector, in reduced coordinates
2085 : !! npw_k=size of the G-vector set
2086 : !!
2087 : !! OUTPUT
2088 : !! kpgnorm(npw_k)=norms of the k+G vectors
2089 : !!
2090 : !! SOURCE
2091 :
2092 306 : subroutine getkpgnorm(gprimd,kpt,kg_k,kpgnorm,npw_k)
2093 :
2094 : !Arguments ------------------------------------
2095 : !scalars
2096 : integer,intent(in) :: npw_k
2097 : !arrays
2098 : integer,intent(in) :: kg_k(3,npw_k)
2099 : real(dp),intent(in) :: gprimd(3,3),kpt(3)
2100 : real(dp),intent(out) :: kpgnorm(npw_k)
2101 :
2102 : !Local variables-------------------------------
2103 : !scalars
2104 : integer :: ipw
2105 : real(dp) :: g11,g12,g13,g21,g22,g23,g31,g32,g33,k1,k2,k3,kpg1,kpg2,kpg3,rr,xx
2106 : real(dp) :: yy,zz
2107 : ! *************************************************************************
2108 :
2109 306 : k1=kpt(1) ; k2=kpt(2) ; k3=kpt(3)
2110 306 : g11=gprimd(1,1)
2111 306 : g12=gprimd(1,2)
2112 306 : g13=gprimd(1,3)
2113 306 : g21=gprimd(2,1)
2114 306 : g22=gprimd(2,2)
2115 306 : g23=gprimd(2,3)
2116 306 : g31=gprimd(3,1)
2117 306 : g32=gprimd(3,2)
2118 306 : g33=gprimd(3,3)
2119 :
2120 : !Loop over all k+G
2121 68931 : do ipw=1,npw_k
2122 :
2123 : ! Load k+G
2124 68625 : kpg1=k1+dble(kg_k(1,ipw))
2125 68625 : kpg2=k2+dble(kg_k(2,ipw))
2126 68625 : kpg3=k3+dble(kg_k(3,ipw))
2127 :
2128 : ! Calculate module of k+G
2129 68625 : xx=g11*kpg1+g12*kpg2+g13*kpg3
2130 68625 : yy=g21*kpg1+g22*kpg2+g23*kpg3
2131 68625 : zz=g31*kpg1+g32*kpg2+g33*kpg3
2132 68625 : rr=sqrt(xx**2+yy**2+zz**2)
2133 68931 : kpgnorm(ipw) = rr
2134 :
2135 : end do ! ipw
2136 :
2137 306 : end subroutine getkpgnorm
2138 : !!***
2139 :
2140 : !!****f* m_gsphere/symg
2141 : !! NAME
2142 : !! symg
2143 : !!
2144 : !! FUNCTION
2145 : !! Treat symmetries applied to the G vectors, in view of the application
2146 : !! to symmetrization of the dielectric matrix.
2147 : !! Generate a list of time-reversed G vectors, as well as a list
2148 : !! of spatially-symmetric G vectors.
2149 : !!
2150 : !! INPUTS
2151 : !! kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
2152 : !! npwdiel=number of planewaves for the dielectric matrix
2153 : !! nsym=number of symmetry
2154 : !! symrel(3,3,nsym)=symmetry matrices in real space (integers)
2155 : !! tnons(3,nsym)=reduced nonsymmorphic translations
2156 : !! (symrel and tnons are in terms of real space primitive translations)
2157 : !!
2158 : !! OUTPUT
2159 : !! phdiel(2,npwdiel,nsym)=phase associated with point symmetries applied to G
2160 : !! sym_g(npwdiel,nsym)=index list of symmetric G vectors
2161 : !! (could save a bit of space by suppressing isym=1, since the
2162 : !! corresponding symmetry is the identity)
2163 : !! tmrev_g(npwdiel)=index list of inverted G vectors (time-reversed)
2164 : !!
2165 : !! SOURCE
2166 :
2167 82 : subroutine symg(kg_diel,npwdiel,nsym,phdiel,sym_g,symrel,tmrev_g,tnons)
2168 :
2169 : !Arguments ------------------------------------
2170 : !scalars
2171 : integer,intent(in) :: npwdiel,nsym
2172 : !arrays
2173 : integer,intent(in) :: kg_diel(3,npwdiel),symrel(3,3,nsym)
2174 : integer,intent(out) :: sym_g(npwdiel,nsym),tmrev_g(npwdiel)
2175 : real(dp),intent(in) :: tnons(3,nsym)
2176 : real(dp),intent(out) :: phdiel(2,npwdiel,nsym)
2177 :
2178 : !Local variables-------------------------------
2179 : !scalars
2180 : integer :: g1,g2,g3,ipw,isym,j1,j2,j3,m1m,m1p,m2m,m2p,m3m,m3p,symmg,trevg
2181 : real(dp) :: arg,tau1,tau2,tau3
2182 : !character(len=500) :: msg
2183 : !arrays
2184 82 : integer,allocatable :: grid(:,:,:)
2185 : ! *************************************************************************
2186 :
2187 : !Determines maximal bounds of the zone spanned by the planewaves
2188 82 : m1m=0 ; m2m=0 ; m3m=0 ; m1p=0 ; m2p=0 ; m3p=0
2189 12500 : do ipw=1,npwdiel
2190 12418 : g1=kg_diel(1,ipw)
2191 12418 : g2=kg_diel(2,ipw)
2192 12418 : g3=kg_diel(3,ipw)
2193 12418 : if(g1<m1m)m1m=g1 ; if(g1>m1p)m1p=g1
2194 12418 : if(g2<m2m)m2m=g2 ; if(g2>m2p)m2p=g2
2195 12500 : if(g3<m3m)m3m=g3 ; if(g3>m3p)m3p=g3
2196 : end do
2197 :
2198 : !Set up grid, that associate to each point the index of the
2199 : !corresponding planewave, if there is one
2200 410 : ABI_MALLOC(grid, (m1m:m1p,m2m:m2p,m3m:m3p))
2201 28718 : grid(:,:,:)=0
2202 12500 : do ipw=1,npwdiel
2203 12418 : g1=kg_diel(1,ipw)
2204 12418 : g2=kg_diel(2,ipw)
2205 12418 : g3=kg_diel(3,ipw)
2206 12500 : grid(g1,g2,g3)=ipw
2207 : end do
2208 :
2209 : !Set up tmrev_g and sym_g arrays
2210 12500 : do ipw=1,npwdiel
2211 12418 : g1=kg_diel(1,ipw)
2212 12418 : g2=kg_diel(2,ipw)
2213 12418 : g3=kg_diel(3,ipw)
2214 :
2215 : ! Treat first time-reversal symmetry
2216 12418 : trevg=grid(-g1,-g2,-g3)
2217 12418 : if(trevg==0)then
2218 0 : ABI_BUG('Do not find the time-reversed symmetric of a G-vector.')
2219 : end if
2220 12418 : tmrev_g(ipw)=trevg
2221 :
2222 : ! Treat now spatial symmetries
2223 98240 : do isym=1,nsym
2224 :
2225 : ! Get rotated G vector Gj for each symmetry element
2226 : ! -- here we use the TRANSPOSE of symrel; assuming symrel expresses
2227 : ! the rotation in real space, the transpose is then appropriate
2228 : ! for G space symmetrization (according to Doug : see routine irrzg.f)
2229 : j1=symrel(1,1,isym)*g1+&
2230 85740 : & symrel(2,1,isym)*g2+symrel(3,1,isym)*g3
2231 : j2=symrel(1,2,isym)*g1+&
2232 85740 : & symrel(2,2,isym)*g2+symrel(3,2,isym)*g3
2233 : j3=symrel(1,3,isym)*g1+&
2234 85740 : & symrel(2,3,isym)*g2+symrel(3,3,isym)*g3
2235 85740 : symmg=grid(j1,j2,j3)
2236 85740 : if(symmg==0)then
2237 0 : ABI_BUG('Do not find the spatially symmetric of a G-vector.')
2238 : end if
2239 85740 : sym_g(ipw,isym)=symmg
2240 :
2241 : ! Get associated phase
2242 85740 : tau1=tnons(1,isym)
2243 85740 : tau2=tnons(2,isym)
2244 85740 : tau3=tnons(3,isym)
2245 98158 : if (abs(tau1)>tol12.or.abs(tau2)>tol12.or.abs(tau3)>tol12) then
2246 : ! compute exp(-2*Pi*I*G dot tau) using original G
2247 31800 : arg=two_pi*(dble(g1)*tau1+dble(g2)*tau2+dble(g3)*tau3)
2248 31800 : phdiel(1,ipw,isym)=cos(arg)
2249 31800 : phdiel(2,ipw,isym)=-sin(arg)
2250 : else
2251 53940 : phdiel(1,ipw,isym)=1._dp
2252 53940 : phdiel(2,ipw,isym)=0._dp
2253 : end if
2254 :
2255 : end do
2256 : end do
2257 :
2258 82 : ABI_FREE(grid)
2259 :
2260 82 : end subroutine symg
2261 : !!***
2262 :
2263 717789 : end module m_gsphere
2264 : !!***
|