Line data Source code
1 : !!****m* ABINIT/m_skw
2 : !! NAME
3 : !! m_skw
4 : !!
5 : !! FUNCTION
6 : !! Shankland-Koelling-Wood Fourier interpolation scheme.
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2008-2026 ABINIT group (MG)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! SOURCE
15 :
16 : #if defined HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #include "abi_common.h"
21 :
22 : module m_skw
23 :
24 : use defs_basis
25 : use m_errors
26 : use m_abicore
27 : use m_xmpi
28 : use m_crystal
29 : use m_sort
30 : use m_nctk
31 : use netcdf
32 :
33 : use m_fstrings, only : itoa, sjoin, ktoa, yesno, ftoa
34 : use m_special_funcs, only : abi_derfc
35 : use m_time, only : cwtime, cwtime_report
36 : use m_numeric_tools, only : imax_loc
37 : use m_bz_mesh, only : isamek
38 : use m_gsphere, only : get_irredg
39 :
40 : implicit none
41 :
42 : private
43 : !!***
44 :
45 : !----------------------------------------------------------------------
46 :
47 : !!****t* m_skw/skw_t
48 : !! NAME
49 : !! skw_t
50 : !!
51 : !! FUNCTION
52 : !! Object implementing the Shankland-Koelling-Wood Fourier interpolation scheme.
53 : !! It can be used to interpolate functions in k-space with the periodicity of the
54 : !! reciprocal lattice and satisfying F(k) = F(Sk) for each rotation S
55 : !! belonging to the point group of the crystal. For readability reason,
56 : !! the names of the variables are chosen assuming we are interpolating electronic eigenvalues
57 : !! but the same object can be used to interpolate phonons as well. Just use nsppol=1 and nband = 3 * natom
58 : !!
59 : !! SOURCE
60 :
61 : type,public :: skw_t
62 :
63 : integer :: cplex
64 : ! 1 if time-reversal symmetry can be used, 2 otherwise.
65 :
66 : integer :: nr
67 : ! Number of star functions.
68 :
69 : integer :: nkpt
70 : ! Number of ab-initio k-points.
71 :
72 : integer :: ptg_nsym
73 : ! Number of operations in the point group.
74 :
75 : logical :: has_inversion
76 : ! True if the point group contains spatial inversion.
77 :
78 : integer :: band_block(2)
79 : ! Initial and final band index.
80 :
81 : integer :: bcount
82 : ! Number of bands
83 :
84 : integer :: nsppol
85 : ! Number of independent spin polarizations.
86 :
87 : integer,allocatable :: rpts(:,:)
88 : ! rpts(3, nr)
89 : ! Real-space lattice points (in reduced coordinates) ordered with non-decreasing length.
90 :
91 : integer,allocatable :: ptg_symrel(:,:,:)
92 : ! ptg_symrel(3,3,ptg_nsym)
93 : ! operations of the point group (real space).
94 :
95 : integer,allocatable :: ptg_symrec(:,:,:)
96 : ! ptg_symrec(3,3,ptg_nsym)
97 : ! operations of the point group (reciprocal space).
98 :
99 : complex(dp),allocatable :: coefs(:,:,:)
100 : ! coefs(nr, bcount, nsppol).
101 :
102 : complex(dp),allocatable :: cached_srk(:)
103 : ! cached_srk(%nr)
104 : ! The star function for cached_kpt (used in skw_eval_bks).
105 : real(dp) :: cached_kpt(3)
106 :
107 : complex(dp),allocatable :: cached_srk_dk1(:,:)
108 : ! cached_srk_dk1(%nr, 3)
109 : ! The 1d derivative wrt k of the star function for cached_kpt_dk1 (used in skw_eval_bks).
110 : real(dp) :: cached_kpt_dk1(3)
111 :
112 : complex(dp),allocatable :: cached_srk_dk2(:,:,:)
113 : ! cached_srk_dk2(%nr,3,3)
114 : ! The 2d derivatives wrt k of the star function for cached_kpt_dk2 (used in skw_eval_bks).
115 : real(dp) :: cached_kpt_dk2(3)
116 :
117 : contains
118 :
119 : procedure :: print => skw_print
120 : ! Print info about object.
121 :
122 : procedure :: ncwrite => skw_ncwrite
123 : ! Write the object in netcdf format
124 :
125 : procedure :: eval_bks => skw_eval_bks
126 : ! Interpolate eigenvalues, 1st, 2nd derivates wrt k, at an arbitrary k-point.
127 :
128 : procedure :: free => skw_free
129 : ! Free memory.
130 :
131 : end type skw_t
132 : !!***
133 :
134 : public :: skw_new ! Create new object.
135 :
136 : CONTAINS !=====================================================================================
137 : !!***
138 :
139 : !!****f* m_skw/skw_new
140 : !! NAME
141 : !! skw_new
142 : !!
143 : !! FUNCTION
144 : !! Initialize the object.
145 : !!
146 : !! INPUTS
147 : !! cryst<crystal_t>=Crystalline structure.
148 : !! params(:)
149 : !! params(1): Ratio between star functions and ab-initio k-points.
150 : !! params(2:3): Activate Fourier filtering (Eq 9 of PhysRevB.61.1639 [[cite:Uehara2000]]) if params(2) > tol6
151 : !! params(2)=rcut, params(3) = rsigma
152 : !! cplex=1 if time reversal can be used, 2 otherwise.
153 : !! nband=Total Number of bands in the eig array.
154 : !! nkpt=Number of ab-initio k-points.
155 : !! nsppol=Number of independent spin polarizations.
156 : !! kpts(3,nkpt)=ab-initio k-points in reduced coordinates.
157 : !! eig(nband,nkpt,nsppol)=ab-initio eigenvalues.
158 : !! band_block(2)=Initial and final band index to interpolate. If [0,0], all bands are used
159 : !! This is a global variable i.e. all MPI procs MUST call the routine with the same value.
160 : !! comm=MPI communicator
161 : !!
162 : !! SOURCE
163 :
164 12 : type(skw_t) function skw_new(cryst, params, cplex, nband, nkpt, nsppol, kpts, eig, band_block, comm) result(new)
165 :
166 : !Arguments ------------------------------------
167 : !scalars
168 : integer,intent(in) :: cplex,nband,nkpt,nsppol,comm
169 : real(dp),intent(in) :: params(:)
170 : type(crystal_t),intent(in) :: cryst
171 : !arrays
172 : integer,intent(in) :: band_block(2)
173 : real(dp),intent(in) :: kpts(3,nkpt)
174 : real(dp),intent(in) :: eig(nband,nkpt,nsppol)
175 :
176 : !Local variables-------------------------------
177 : !scalars
178 : integer,parameter :: master=0,prtvol=1
179 : integer :: my_rank,nprocs,cnt,bstop,bstart,bcount,lwork
180 : integer :: ir,ik,ib,ii,jj,nr,band,spin,ierr,lpratio,nrwant
181 : real(dp),parameter :: c1=0.25_dp,c2=0.25_dp
182 : real(dp) :: r2,r2min,mare,mae_meV,adiff_meV,rel_err,rcut,rsigma
183 : real(dp) :: cpu_tot,wall_tot,gflops_tot,cpu,wall,gflops,rval
184 : character(len=500) :: fmt,msg
185 : !arrays
186 : integer :: rmax(3)
187 6 : integer,allocatable :: ipiv(:)
188 : real(dp) :: list2(2)
189 6 : real(dp),allocatable :: r2vals(:),inv_rhor(:),oeig(:)
190 6 : complex(dp),allocatable :: srk(:,:),hmat(:,:),lambda(:,:,:),work(:)
191 : ! *********************************************************************
192 :
193 6 : ABI_CHECK(nkpt > 1, sjoin("nkpt must be > 1 but got:", itoa(nkpt)))
194 :
195 6 : call cwtime(cpu_tot, wall_tot, gflops_tot, "start")
196 :
197 6 : nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
198 :
199 : ! Get slice of bands to be treated.
200 18 : new%band_block = band_block; if (all(band_block == 0)) new%band_block = [1, nband]
201 6 : bstart = new%band_block(1); bstop = new%band_block(2); bcount = bstop - bstart + 1
202 6 : new%cplex = cplex; new%nkpt = nkpt; new%nsppol = nsppol; new%bcount = bcount
203 :
204 : ! Get point group operations.
205 6 : call cryst%get_point_group(new%ptg_nsym, new%ptg_symrel, new%ptg_symrec, new%has_inversion, include_timrev=cplex==1)
206 :
207 : ! -----------------------
208 : ! Find nrwant star points
209 : ! -----------------------
210 6 : lpratio = int(abs(params(1)))
211 6 : ABI_CHECK(lpratio > 0, "lpratio must be > 0")
212 24 : rmax = nint((one + (lpratio * new%nkpt * new%ptg_nsym) / two) ** third)
213 6 : if (new%has_inversion) then
214 24 : rmax = nint((one + (lpratio * new%nkpt * new%ptg_nsym / 2) / two) ** third)
215 : end if
216 6 : nrwant = lpratio * new%nkpt
217 :
218 6 : call cwtime(cpu, wall, gflops, "start")
219 0 : do
220 6 : call find_rstar_gen(new, cryst, nrwant, rmax, r2vals, comm)
221 6 : if (new%nr >= nrwant) then
222 : !write(std_out,*)"Entered with rmax", rmax," abs(skw%rpts(last)): ", abs(new%rpts(:,new%nr))
223 : exit
224 : end if
225 0 : write(std_out,*)"rmax: ", rmax," was not large enough to find ", nrwant," R-star points."
226 0 : rmax = 2 * rmax
227 0 : write(std_out,*)"Will try again with enlarged rmax: ",rmax
228 0 : ABI_FREE(r2vals)
229 : end do
230 6 : nr = new%nr
231 6 : call cwtime_report(" find_rstar_gen", cpu, wall, gflops)
232 :
233 6 : if (my_rank == master) call new%print(std_out)
234 :
235 : ! Compute (inverse) roughness function.
236 6 : r2min = r2vals(2)
237 18 : ABI_MALLOC(inv_rhor, (nr))
238 341 : do ir=1,nr
239 335 : r2 = r2vals(ir)
240 341 : inv_rhor(ir) = one / ((one - c1 * r2/r2min)**2 + c2 * (r2 / r2min)**3)
241 : ! TODO: Test the two versions.
242 : !if (params(1) < zero) inv_rhor(ir) = one / (c1 * r2 + c2 * r2**2)
243 : end do
244 :
245 : ! Construct star functions for the ab-initio k-points.
246 24 : ABI_MALLOC(srk, (nr, nkpt))
247 73 : do ik=1,nkpt
248 73 : call mkstar(new, kpts(:,ik), srk(:,ik))
249 : end do
250 :
251 : ! Build H(k,k') matrix (Hermitian)
252 1090 : ABI_CALLOC(hmat, (nkpt-1, nkpt-1))
253 : cnt = 0
254 67 : do jj=1,nkpt-1
255 600 : do ii=1,jj
256 : !do ii=1,nkpt-1
257 533 : cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! mpi parallelism.
258 63861 : do ir=2,nr
259 : hmat(ii, jj) = hmat(ii, jj) + &
260 63800 : (srk(ir, ii) - srk(ir, nkpt)) * conjg(srk(ir, jj) - srk(ir, nkpt)) * inv_rhor(ir)
261 : end do
262 : end do
263 : end do
264 6 : call xmpi_sum(hmat, comm, ierr)
265 :
266 30 : ABI_MALLOC(lambda, (nkpt-1, bcount, nsppol))
267 12 : do spin=1,nsppol
268 88 : do ib=1,bcount
269 76 : band = ib + bstart - 1
270 754 : lambda(:,ib,spin) = eig(band,1:nkpt-1,spin) - eig(band,nkpt,spin)
271 : end do
272 : end do
273 :
274 : ! Solve all bands and spins at once [[cite:Pickett1988]]
275 6 : call wrtout(std_out, " Solving system of linear equations to get lambda coeffients (eq. 10 of PRB 38 2721)...", do_flush=.True.)
276 6 : call cwtime(cpu, wall, gflops, "start")
277 18 : ABI_MALLOC(ipiv, (nkpt-1))
278 :
279 : if (.False.) then
280 : ! General complex.
281 : call zgesv(nkpt-1, bcount*nsppol, hmat, nkpt-1, ipiv, lambda, nkpt-1, ierr)
282 : ABI_CHECK(ierr == 0, sjoin("ZGESV returned:", itoa(ierr)))
283 : else
284 : ! Hermitian version
285 67 : do ii=1,nkpt-1
286 67 : hmat(ii, ii) = real(hmat(ii, ii))
287 : end do
288 6 : lwork = -1
289 6 : ABI_MALLOC(work, (1))
290 6 : call zhesv("U", nkpt-1, bcount*nsppol, hmat, nkpt-1, ipiv, lambda, nkpt-1, work, lwork, ierr)
291 6 : lwork = nint(real(work(1)))
292 6 : ABI_FREE(work)
293 18 : ABI_MALLOC(work, (lwork))
294 6 : call zhesv("U", nkpt-1, bcount*nsppol, hmat, nkpt-1, ipiv, lambda, nkpt-1, work, lwork, ierr)
295 6 : ABI_CHECK(ierr == 0, sjoin("ZHESV returned:", itoa(ierr)))
296 6 : ABI_FREE(work)
297 : end if
298 6 : call cwtime_report(" ZHESV", cpu, wall, gflops)
299 :
300 : ! Compute coefficients
301 30 : ABI_MALLOC(new%coefs, (nr,bcount,nsppol))
302 :
303 12 : do spin=1,nsppol
304 88 : do ib=1,bcount
305 76 : band = ib + bstart - 1
306 3740 : do ir=2,nr
307 52768 : new%coefs(ir,ib,spin) = inv_rhor(ir) * dot_product(srk(ir,:nkpt-1) - srk(ir,nkpt), lambda(:nkpt-1, ib, spin))
308 : !new%coefs(ir,ib,spin) = inv_rhor(ir) * dot_product(lambda(:nkpt-1, ib, spin), conjg(srk(ir,:) - srk(ir,nkpt)))
309 : !new%coefs(ir,ib,spin) = inv_rhor(ir) * dot_product(lambda(:nkpt-1, ib, spin), conjg(srk(ir,:) - srk(ir,1)))
310 : end do
311 3746 : new%coefs(1,ib,spin) = eig(band,nkpt,spin) - dot_product(conjg(new%coefs(2:nr, ib,spin)), srk(2:nr, nkpt))
312 : end do
313 : end do
314 :
315 : ! Filter high-frequency.
316 6 : if (params(2) > tol6) then
317 0 : rcut = params(2) * sqrt(r2vals(new%nr))
318 0 : rsigma = params(3); if (rsigma <= zero) rsigma = five
319 0 : call wrtout(std_out," Applying filter (Eq 9 of PhysRevB.61.1639)") ! [[cite:Uehara2000]]
320 0 : do ir=2,nr
321 0 : new%coefs(ir,:,:) = new%coefs(ir,:,:) * half * abi_derfc((sqrt(r2vals(ir)) - rcut) / rsigma)
322 : end do
323 : end if
324 :
325 : ! Prepare workspace arrays for star functions.
326 24 : new%cached_kpt = huge(one)
327 18 : ABI_MALLOC(new%cached_srk, (new%nr))
328 24 : new%cached_kpt_dk1 = huge(one)
329 18 : ABI_MALLOC(new%cached_srk_dk1, (new%nr, 3))
330 24 : new%cached_kpt_dk2 = huge(one)
331 24 : ABI_MALLOC(new%cached_srk_dk2, (new%nr, 3, 3))
332 :
333 6 : ABI_FREE(r2vals)
334 6 : ABI_FREE(srk)
335 6 : ABI_FREE(inv_rhor)
336 6 : ABI_FREE(hmat)
337 6 : ABI_FREE(lambda)
338 6 : ABI_FREE(ipiv)
339 :
340 : ! Compare ab-initio data with interpolated results.
341 18 : ABI_MALLOC(oeig, (bcount))
342 6 : fmt = sjoin("(a,", itoa(bcount), "(es12.4))")
343 6 : bstop = bstart + bcount - 1
344 6 : mare = zero; mae_meV = zero; cnt = 0
345 6 : call wrtout(std_out, ch10//" Comparing ab-initio energies with SKW interpolated results...")
346 12 : do spin=1,nsppol
347 79 : do ik=1,nkpt
348 67 : cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! mpi parallelism.
349 :
350 815 : do ib=1,bcount
351 748 : band = ib + new%band_block(1) - 1
352 748 : call new%eval_bks(band, kpts(:,ik), spin, oeig(ib))
353 :
354 748 : adiff_meV = abs(eig(band,ik,spin) - oeig(ib)); rel_err = zero
355 748 : if (abs(eig(band,ik,spin)) > tol16) rel_err = adiff_meV / abs(eig(band,ik,spin))
356 748 : rel_err = 100 * rel_err; adiff_meV = adiff_meV * Ha_meV
357 815 : mae_meV = mae_meV + adiff_meV; mare = mare + rel_err
358 : end do
359 :
360 6 : if (prtvol > 0) then
361 815 : ib = imax_loc(eig(bstart:bstop,ik,spin) - oeig)
362 67 : rval = (eig(bstart+ib-1,ik,spin) - oeig(ib)) * Ha_meV
363 : write(std_out,"(a,es12.4,2a)") &
364 67 : " SKW maxerr: ", rval, &
365 134 : " (meV), kpt: ", sjoin(ktoa(kpts(:,ik)), "band:",itoa(bstart+ib-1),", spin: ", itoa(spin))
366 : !write(std_out,fmt)"-- ref ", eig(bstart:bstop,ik,spin) * Ha_meV
367 : !write(std_out,fmt)"-- int ", oeig * Ha_meV
368 : !call vdiff%eval(1, bcount, eig(bstart:bstop,ik,spin), oeig, one, unit=std_out))
369 : end if
370 : end do
371 : end do
372 6 : ABI_FREE(oeig)
373 :
374 : ! Issue warning if error too large.
375 18 : list2 = [mare, mae_meV]; call xmpi_sum(list2, comm, ierr); mare = list2(1); mae_meV = list2(2)
376 6 : cnt = bcount * nkpt * nsppol; mare = mare / cnt; mae_meV = mae_meV / cnt
377 6 : write(std_out,"(2(a,es12.4),a,/)")" MARE: ",mare, ", MAE: ", mae_meV, " (meV)"
378 6 : if (mae_meV > ten) then
379 : write(msg,"(2a,2(a,es12.4),a)") &
380 0 : "Large error in SKW interpolation!",ch10," MARE: ",mare, ", MAE: ", mae_meV, " (meV)"
381 0 : call wrtout(ab_out, msg)
382 0 : ABI_WARNING(msg)
383 : end if
384 :
385 6 : call cwtime_report(" skw_new", cpu_tot, wall_tot, gflops_tot, end_str=ch10)
386 :
387 48 : end function skw_new
388 : !!***
389 :
390 : !----------------------------------------------------------------------
391 :
392 : !!****f* m_skw/skw_print
393 : !! NAME
394 : !! skw_print
395 : !!
396 : !! FUNCTION
397 : !! Print info on object
398 : !!
399 : !! INPUTS
400 : !! unt=Fortran unit number.
401 : !!
402 : !! OUTPUT
403 : !! only writing
404 : !!
405 : !! SOURCE
406 :
407 6 : subroutine skw_print(skw, unt)
408 :
409 : !Arguments ------------------------------------
410 : !scalars
411 : class(skw_t),intent(in) :: skw
412 : integer,intent(in) :: unt
413 :
414 : ! *********************************************************************
415 :
416 6 : write(unt,"(a)")" === Shankland-Koelling-Wood Fourier interpolation scheme ==="
417 6 : write(unt,"(a)")sjoin(" nsppol", itoa(skw%nsppol), ", cplex:", itoa(skw%cplex))
418 6 : write(unt,"(a)")sjoin(" Number of ab-initio k-points:", itoa(skw%nkpt))
419 6 : write(unt,"(a)")sjoin(" Number of star functions:", itoa(skw%nr))
420 6 : write(unt,"(a)")sjoin(" Stars/Nk ratio:", ftoa(skw%nr * one / skw%nkpt))
421 6 : write(unt,"(a)")sjoin(" Has spatial inversion:", yesno(skw%has_inversion))
422 :
423 6 : end subroutine skw_print
424 : !!***
425 :
426 : !----------------------------------------------------------------------
427 :
428 : !!****f* m_skw/skw_ncwrite
429 : !! NAME
430 : !! skw_ncwrite
431 : !!
432 : !! FUNCTION
433 : !! Write the object in netcdf format
434 : !!
435 : !! INPUTS
436 : !! ncid=NC file handle.
437 : !! [prefix]=String prepended to netcdf dimensions/variables (HDF5 poor-man groups)
438 : !! "skw" if not specified.
439 : !!
440 : !! OUTPUT
441 : !! Only writing
442 : !!
443 : !! SOURCE
444 :
445 0 : integer function skw_ncwrite(self, ncid, prefix) result(ncerr)
446 :
447 : !Arguments ------------------------------------
448 : !scalars
449 : class(skw_t),intent(in) :: self
450 : integer,intent(in) :: ncid
451 : character(len=*),optional,intent(in) :: prefix
452 :
453 : !Local variables-------------------------------
454 : !scalars
455 : character(len=500) :: prefix_
456 : !arrays
457 0 : real(dp),allocatable :: real_coefs(:,:,:,:)
458 : ! *************************************************************************
459 :
460 0 : prefix_ = "skw"; if (present(prefix)) prefix_ = trim(prefix)
461 :
462 : ! Define dimensions.
463 : ncerr = nctk_def_dims(ncid, [ &
464 : nctkdim_t("nr", self%nr), nctkdim_t("nkpt", self%nkpt), nctkdim_t("bcount", self%bcount), &
465 : nctkdim_t("nsppol", self%nsppol)], &
466 0 : defmode=.True., prefix=prefix_)
467 0 : NCF_CHECK(ncerr)
468 :
469 : ncerr = nctk_def_arrays(ncid, [ &
470 : ! Atomic structure and symmetry operations
471 : nctkarr_t("rpts", "dp", "three, number_of_cartesian_directions, number_of_vectors"), &
472 : nctkarr_t("kpts", "dp", "three, nkpt"), &
473 : nctkarr_t("coefs", "dp", "two, nr, bcount, nsppol") &
474 0 : ], prefix=prefix_)
475 0 : NCF_CHECK(ncerr)
476 :
477 : ! Write data.
478 0 : NCF_CHECK(nctk_set_datamode(ncid))
479 0 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, pre("rpts")), self%rpts))
480 : !NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, pre("kpts")), self%kpts))
481 0 : ABI_MALLOC(real_coefs, (2, self%nr, self%bcount, self%nsppol))
482 0 : real_coefs(1,:,:,:) = real(self%coefs); real_coefs(2,:,:,:) = aimag(self%coefs)
483 0 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, pre("coefs")), real_coefs))
484 0 : ABI_FREE(real_coefs)
485 :
486 : contains
487 0 : pure function pre(istr) result(ostr)
488 : character(len=*),intent(in) :: istr
489 : character(len=len_trim(prefix_) + len_trim(istr)+1) :: ostr
490 0 : ostr = trim(prefix_) // trim(istr)
491 0 : end function pre
492 :
493 : end function skw_ncwrite
494 : !!***
495 :
496 : !!****f* m_skw/skw_eval_bks
497 : !! NAME
498 : !! skw_eval_bks
499 : !!
500 : !! FUNCTION
501 : !! Interpolate the energies for an arbitrary k-point and spin with slow FT.
502 : !!
503 : !! INPUTS
504 : !! band=Band index (global index associated to the input eigenvalues, i.e. independent of band_block)
505 : !! kpt(3)=K-point in reduced coordinates.
506 : !! spin=Spin index.
507 : !!
508 : !! OUTPUT
509 : !! oeig=interpolated eigenvalues
510 : !! Note that oeig is not necessarily sorted in ascending order.
511 : !! The routine does not reorder the interpolated eigenvalues
512 : !! to be consistent with the interpolation of the derivatives.
513 : !! [oder1(3)]=First-order derivatives wrt k in reduced coordinates.
514 : !! [oder2(3,3)]=Second-order derivatives wrt k in reduced coordinates.
515 : !!
516 : !! SOURCE
517 :
518 13434 : subroutine skw_eval_bks(skw, band, kpt, spin, oeig, oder1, oder2)
519 :
520 : !Arguments ------------------------------------
521 : !scalars
522 : integer,intent(in) :: band,spin
523 : class(skw_t),intent(inout) :: skw
524 : !arrays
525 : real(dp),intent(in) :: kpt(3)
526 : real(dp),intent(out) :: oeig
527 : real(dp),optional,intent(out) :: oder1(3),oder2(3,3)
528 :
529 : !Local variables-------------------------------
530 : !scalars
531 : integer :: ii,jj,ib
532 : ! *********************************************************************
533 :
534 13434 : ib = band - skw%band_block(1) + 1
535 13434 : ABI_CHECK(ib >= 1 .and. ib <= skw%bcount, sjoin("out of range band:", itoa(band)))
536 :
537 : ! Compute star function for this k-point (if not already in memory)
538 50579 : if (any(kpt /= skw%cached_kpt)) then
539 1098 : call mkstar(skw, kpt, skw%cached_srk)
540 4392 : skw%cached_kpt = kpt
541 : end if
542 :
543 854314 : oeig = dot_product(conjg(skw%coefs(:,ib,spin)), skw%cached_srk)
544 :
545 : ! TODO: Test Derivatives
546 13434 : if (present(oder1)) then
547 : ! Compute first-order derivatives.
548 0 : if (any(kpt /= skw%cached_kpt_dk1)) then
549 0 : call mkstar_dk1(skw, kpt, skw%cached_srk_dk1)
550 0 : skw%cached_kpt_dk1 = kpt
551 : end if
552 :
553 0 : do ii=1,3
554 0 : oder1(ii) = dot_product(conjg(skw%coefs(:,ib,spin)), skw%cached_srk_dk1(:,ii)) * two_pi
555 : end do
556 : end if
557 :
558 13434 : if (present(oder2)) then
559 : ! Compute second-order derivatives.
560 0 : if (any(kpt /= skw%cached_kpt_dk2)) then
561 0 : call mkstar_dk2(skw, kpt, skw%cached_srk_dk2)
562 0 : skw%cached_kpt_dk2 = kpt
563 : end if
564 :
565 0 : oder2 = zero
566 0 : do jj=1,3
567 0 : do ii=1,jj
568 0 : oder2(ii, jj) = dot_product(conjg(skw%coefs(:,ib,spin)), skw%cached_srk_dk2(:,ii,jj)) * two_pi**2
569 0 : if (ii /= jj) oder2(jj, ii) = oder2(ii, jj)
570 : end do
571 : end do
572 : end if
573 :
574 13434 : end subroutine skw_eval_bks
575 : !!***
576 :
577 : !----------------------------------------------------------------------
578 :
579 : !!****f* m_skw/skw_free
580 : !! NAME
581 : !! skw_free
582 : !!
583 : !! FUNCTION
584 : !! Free memory
585 : !!
586 : !! SOURCE
587 :
588 6 : subroutine skw_free(skw)
589 :
590 : !Arguments ------------------------------------
591 : !scalars
592 : class(skw_t),intent(inout) :: skw
593 :
594 : ! *********************************************************************
595 :
596 6 : ABI_SFREE(skw%rpts)
597 6 : ABI_SFREE(skw%ptg_symrel)
598 6 : ABI_SFREE(skw%ptg_symrec)
599 6 : ABI_SFREE(skw%coefs)
600 :
601 6 : ABI_SFREE(skw%cached_srk)
602 24 : skw%cached_kpt = huge(one)
603 6 : ABI_SFREE(skw%cached_srk_dk1)
604 24 : skw%cached_kpt_dk1 = huge(one)
605 6 : ABI_SFREE(skw%cached_srk_dk2)
606 24 : skw%cached_kpt_dk2 = huge(one)
607 :
608 6 : end subroutine skw_free
609 : !!***
610 :
611 : !----------------------------------------------------------------------
612 :
613 : !!****f* m_skw/mkstar
614 : !! NAME
615 : !! mkstar
616 : !!
617 : !! FUNCTION
618 : !! Compute the star function for k-point kpt
619 : !!
620 : !! INPUTS
621 : !! kpt(3)=K-point in reduced coordinates.
622 : !!
623 : !! OUTPUT
624 : !! srk(%nr)=Star function for this k-point.
625 : !!
626 : !! SOURCE
627 :
628 1165 : subroutine mkstar(skw, kpt, srk)
629 :
630 : !Arguments ------------------------------------
631 : !scalars
632 : type(skw_t),intent(in) :: skw
633 : !arrays
634 : real(dp),intent(in) :: kpt(3)
635 : complex(dp),intent(out) :: srk(skw%nr)
636 :
637 : !Local variables-------------------------------
638 : !scalars
639 : integer :: ir,isym
640 : !arrays
641 : real(dp) :: sk(3)
642 : ! *********************************************************************
643 :
644 91745 : srk = zero
645 57085 : do isym=1,skw%ptg_nsym
646 1621680 : sk = two_pi * matmul(transpose(skw%ptg_symrel(:,:,isym)), kpt)
647 4404925 : do ir=1,skw%nr
648 17447280 : srk(ir) = srk(ir) + exp(j_dpc * dot_product(sk, skw%rpts(:,ir)))
649 : end do
650 : end do
651 91745 : srk = srk / skw%ptg_nsym
652 :
653 1165 : end subroutine mkstar
654 : !!***
655 :
656 : !----------------------------------------------------------------------
657 :
658 : !!****f* m_skw/mkstar_dk1
659 : !! NAME
660 : !! mkstar_dk1
661 : !!
662 : !! FUNCTION
663 : !! Compute the 1st derivative of the star function wrt k
664 : !!
665 : !! INPUTS
666 : !! kpt(3)=K-point in reduced coordinates.
667 : !!
668 : !! OUTPUT
669 : !! srk_dk1(%nr,3)=Derivative of the star function wrt k in reduced coordinates.
670 : !!
671 : !! SOURCE
672 :
673 0 : subroutine mkstar_dk1(skw, kpt, srk_dk1)
674 :
675 : !Arguments ------------------------------------
676 : !scalars
677 : type(skw_t),intent(in) :: skw
678 : !arrays
679 : real(dp),intent(in) :: kpt(3)
680 : complex(dp),intent(out) :: srk_dk1(skw%nr,3)
681 :
682 : !Local variables-------------------------------
683 : !scalars
684 : integer :: ir,isym
685 : !arrays
686 : real(dp) :: sk(3)
687 0 : complex(dp) :: work(3,skw%nr)
688 : ! *********************************************************************
689 :
690 0 : work = zero
691 0 : do isym=1,skw%ptg_nsym
692 0 : sk = two_pi * matmul(transpose(skw%ptg_symrel(:,:,isym)), kpt)
693 0 : do ir=1,skw%nr
694 : work(:,ir) = work(:,ir) + exp(j_dpc * dot_product(sk, skw%rpts(:,ir))) * &
695 0 : matmul(skw%ptg_symrel(:,:,isym), skw%rpts(:,ir))
696 : end do
697 : end do
698 0 : work = j_dpc * work / skw%ptg_nsym
699 0 : srk_dk1 = transpose(work)
700 :
701 0 : end subroutine mkstar_dk1
702 : !!***
703 :
704 : !----------------------------------------------------------------------
705 :
706 : !!****f* m_skw/mkstar_dk2
707 : !! NAME
708 : !! mkstar_dk2
709 : !!
710 : !! FUNCTION
711 : !! Compute the 2st derivatives of the star function wrt k
712 : !!
713 : !! INPUTS
714 : !! kpt(3)=K-point in reduced coordinates.
715 : !!
716 : !! OUTPUT
717 : !! srk_dk2(%nr,3,3)=2nd derivatives of the star function wrt k in reduced coordinates.
718 : !!
719 : !! SOURCE
720 :
721 0 : subroutine mkstar_dk2(skw, kpt, srk_dk2)
722 :
723 : !Arguments ------------------------------------
724 : !scalars
725 : type(skw_t),intent(in) :: skw
726 : !arrays
727 : real(dp),intent(in) :: kpt(3)
728 : complex(dp),intent(out) :: srk_dk2(skw%nr,3,3)
729 :
730 : !Local variables-------------------------------
731 : !scalars
732 : integer :: ir,isym,ii,jj
733 : complex(dp) :: eiskr
734 : !arrays
735 : integer :: sr(3)
736 : real(dp) :: sk(3)
737 0 : complex(dp) :: work(3,3,skw%nr)
738 : ! *********************************************************************
739 :
740 0 : work = zero
741 0 : do isym=1,skw%ptg_nsym
742 0 : sk = two_pi * matmul(transpose(skw%ptg_symrel(:,:,isym)), kpt)
743 0 : do ir=1,skw%nr
744 0 : sr = matmul(skw%ptg_symrel(:,:,isym), skw%rpts(:,ir))
745 0 : eiskr = exp(j_dpc * dot_product(sk, skw%rpts(:,ir)))
746 0 : do jj=1,3
747 0 : do ii=1,jj
748 0 : work(ii,jj,ir) = work(ii,jj,ir) + eiskr * sr(ii) * sr(jj)
749 : end do
750 : end do
751 : end do
752 : end do
753 0 : work = - work / skw%ptg_nsym
754 :
755 0 : do jj=1,3
756 0 : do ii=1,jj
757 0 : srk_dk2(:, ii, jj) = work(ii, jj, :)
758 0 : if (ii /= jj) srk_dk2(:,jj,ii) = work(:,ii,jj)
759 : end do
760 : end do
761 :
762 0 : end subroutine mkstar_dk2
763 : !!***
764 :
765 : !----------------------------------------------------------------------
766 :
767 : !!****f* m_skw/find_rstar_gen
768 : !! NAME
769 : !! find_rstar_gen
770 : !!
771 : !! FUNCTION
772 : !! Find the R-space points generating the stars.
773 : !! Set skw%nr and skw%rpts.
774 : !!
775 : !! INPUTS
776 : !! cryst<crystal_t>=Crystalline structure.
777 : !! nrwant=Number of R-space points wanted
778 : !! rmax(3)=Max reduced components of supercell.
779 : !! comm=MPI communicator.
780 : !!
781 : !! OUTPUT
782 : !! or2vals(skw%nr)=||R||**2
783 : !!
784 : !! SOURCE
785 :
786 6 : subroutine find_rstar_gen(skw, cryst, nrwant, rmax, or2vals, comm)
787 :
788 : !Arguments ------------------------------------
789 : !scalars
790 : type(skw_t),intent(inout) :: skw
791 : type(crystal_t),intent(in) :: cryst
792 : integer,intent(in) :: nrwant,comm
793 : !arrays
794 : integer,intent(in) :: rmax(3)
795 : real(dp),allocatable,intent(out) :: or2vals(:)
796 :
797 : !Local variables-------------------------------
798 : !scalars
799 : integer :: cnt,nstars,i1,i2,i3,msize,ir,nsh,ish,ss,ee,nst,ierr,nprocs,my_rank,ii
800 : real(dp) :: r2_prev
801 : !character(len=500) :: msg
802 : !arrays
803 6 : integer,allocatable :: iperm(:),rtmp(:,:),rgen(:,:),r2sh(:),shlim(:),sh_start(:),sh_stop(:)
804 6 : integer,allocatable :: recvcounts(:),displs(:),recvbuf(:,:)
805 6 : real(dp),allocatable :: r2tmp(:),cnorm(:)
806 :
807 : ! *********************************************************************
808 :
809 6 : nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
810 :
811 24 : msize = product(2*rmax + 1)
812 18 : ABI_MALLOC(rtmp, (3, msize))
813 18 : ABI_MALLOC(r2tmp, (msize))
814 :
815 6 : cnt = 0
816 114 : do i3=-rmax(3),rmax(3)
817 2120 : do i2=-rmax(2),rmax(2)
818 40766 : do i1=-rmax(1),rmax(1)
819 38652 : cnt = cnt + 1
820 154608 : rtmp(:, cnt) = [i1,i2,i3]
821 775046 : r2tmp(cnt) = dot_product(rtmp(:,cnt), matmul(cryst%rmet, rtmp(:,cnt)))
822 : end do
823 : end do
824 : end do
825 :
826 : ! Sort r2tmp
827 18 : ABI_MALLOC(iperm, (msize))
828 115974 : iperm = [(i1, i1=1,msize)]
829 6 : call sort_dp(msize, r2tmp, iperm, tol12)
830 :
831 : ! Find R-points generating the stars.
832 12 : ABI_MALLOC(rgen, (3, msize))
833 38658 : do ir=1,msize
834 154614 : rgen(:,ir) = rtmp(:,iperm(ir))
835 : end do
836 154620 : rtmp = rgen
837 6 : ABI_FREE(iperm)
838 :
839 12 : ABI_MALLOC(r2sh, (msize)) ! Correspondence between R and the shell index.
840 18 : ABI_MALLOC(shlim, (msize+1)) ! For each shell, the index of the initial G-vector.
841 6 : nsh = 1; r2sh(1) = 1; shlim(1) = 1; r2_prev = zero
842 38652 : do ir=2,msize
843 38646 : if (abs(r2tmp(ir) - r2_prev) > r2tmp(ir) * tol8) then
844 1267 : r2_prev = r2tmp(ir); nsh = nsh + 1; shlim(nsh) = ir
845 : !write(std_out,*)"nsh: ",shlim(nsh) - shlim(nsh-1)
846 : end if
847 38652 : r2sh(ir) = nsh
848 : end do
849 6 : shlim(nsh+1) = msize + 1
850 6 : ABI_FREE(r2tmp)
851 6 : ABI_FREE(r2sh)
852 :
853 : !call get_irredg(msize, skw%ptg_nsym, +1, cryst%rprimd, skw%ptg_symrel, rtmp, nstars, rgen, cnorm)
854 : !write(66,*)nstars; do ish=1,nstars; write(66,*)rgen(:,ish); end do
855 :
856 : ! Distribute shells among processor so that we can parallelize the search algorithm.
857 : ! Each proc works on a contigous block of shells, then we have to gather the results.
858 18 : ABI_MALLOC(sh_start, (0:nprocs-1))
859 12 : ABI_MALLOC(sh_stop, (0:nprocs-1))
860 6 : call xmpi_split_work2_i4b(nsh, nprocs, sh_start, sh_stop)
861 :
862 12 : ABI_MALLOC(cnorm, (msize))
863 6 : nstars = 0
864 1279 : do ish=sh_start(my_rank),sh_stop(my_rank)
865 1273 : ss = shlim(ish); ee = shlim(ish+1) - 1; msize = ee - ss + 1
866 : call get_irredg(msize, skw%ptg_nsym, + 1, cryst%rprimd, skw%ptg_symrel, rtmp(:,ss:), &
867 1273 : nst, rgen(:,nstars+1:), cnorm(nstars+1:))
868 1279 : nstars = nstars + nst
869 : end do
870 :
871 6 : ABI_FREE(cnorm)
872 6 : ABI_FREE(sh_start)
873 6 : ABI_FREE(sh_stop)
874 6 : ABI_FREE(rtmp)
875 6 : ABI_FREE(shlim)
876 :
877 6 : if (nprocs > 1) then
878 : ! Collect star functions.
879 0 : ABI_MALLOC(recvcounts, (nprocs))
880 0 : recvcounts = 0; recvcounts(my_rank+1) = 3 * nstars
881 0 : call xmpi_sum(recvcounts, comm, ierr)
882 0 : ABI_MALLOC(displs, (nprocs))
883 0 : displs(1) = 0
884 0 : do ii=2,nprocs
885 0 : displs(ii) = sum(recvcounts(:ii-1))
886 : end do
887 0 : call xmpi_sum(nstars, nst, comm, ierr) ! Now nst is the total number of star functions.
888 0 : ABI_MALLOC(recvbuf, (3, nst))
889 0 : call xmpi_allgatherv(rgen, 3*nstars, recvbuf, recvcounts, displs, comm, ierr)
890 0 : ABI_FREE(recvcounts)
891 0 : ABI_FREE(displs)
892 0 : nstars = nst
893 0 : rgen(:,1:nstars) = recvbuf
894 0 : ABI_FREE(recvbuf)
895 : end if
896 : !if (my_rank == 0) then
897 : ! write(67,*)"nstars",nstars,"nsh",nsh; do ish=1,nstars; write(67,*)rgen(:,ish); end do
898 : !end if
899 :
900 : ! Store rpts and compute ||R||**2.
901 6 : skw%nr = min(nstars, nrwant)
902 6 : if (allocated(skw%rpts)) then
903 0 : ABI_FREE(skw%rpts)
904 : end if
905 18 : ABI_MALLOC(skw%rpts, (3, skw%nr))
906 1352 : skw%rpts = rgen(:,1:skw%nr)
907 18 : ABI_MALLOC(or2vals, (skw%nr))
908 341 : do ir=1,skw%nr
909 6706 : or2vals(ir) = dot_product(skw%rpts(:,ir), matmul(cryst%rmet, skw%rpts(:,ir)))
910 : end do
911 :
912 6 : ABI_FREE(rgen)
913 :
914 6 : end subroutine find_rstar_gen
915 : !!***
916 :
917 94907 : end module m_skw
918 : !!***
|