Line data Source code
1 : !!****m*ABINIT/m_wannier_builder
2 : !! NAME
3 : !! m_wannier_builder
4 : !!
5 : !! FUNCTION
6 : !! Algorithms for building Wannier functions
7 : !! Methods:
8 : !! SCDM (select columns of density matrix method) and
9 : !! projected wannier function (PWF)
10 : !! COPYRIGHT
11 : !! Copyright (C) 2005-2026 ABINIT group (hexu)
12 : !! This file is distributed under the terms of the
13 : !! GNU General Public License, see ~abinit/COPYING
14 : !! or http://www.gnu.org/copyleft/gpl.txt .
15 : !!
16 : !! SOURCE
17 : !!
18 : !! Todolist:
19 : !! - output of Wannier90 format Amn, Mmn, eigenvalue files
20 : !! - output header in netcdf file
21 : !! - allow units in Hamiltonian
22 : !! - projected wannier functions
23 :
24 : #if defined HAVE_CONFIG_H
25 : #include "config.h"
26 : #endif
27 :
28 :
29 : #include "abi_common.h"
30 :
31 :
32 : !===============================================================
33 : ! SCDM-k
34 : !> @description: Select Column Density matrix method for
35 : ! generating Wannier functions.
36 : !===============================================================
37 : module m_wannier_builder
38 : use defs_basis
39 : use m_abicore
40 : use m_errors
41 : use m_io_tools, only : open_file
42 : use m_fstrings, only : ltoa
43 : use m_scdm_math, only: complex_QRCP_piv_only, complex_svd, tpi_im, &
44 : & gaussian, fermi, insertion_sort_double, eigensolver
45 : use m_wann_netcdf, only: IOWannNC
46 : implicit none
47 : public:: WannierBuilder_t
48 : public :: WannierBuilder_witheigen_t
49 : public:: Amn_to_H
50 : private
51 :
52 :
53 : !===============================================================
54 : ! WannierBuilder_t type:
55 : !> @ description: the class for scdmk method.
56 : !===============================================================
57 : type:: WannierBuilder_t
58 :
59 : ! Inputs
60 : real(dp), allocatable:: kpts(:, :) !(idim, ikpt)
61 : real(dp), allocatable:: kweights(:) !(ikpt)
62 : !real(dp), allocatable:: weight(:, :) !(iband, ikpt)
63 : integer, allocatable:: exclude_bands(:)
64 :
65 : integer:: method = 0 ! 1: SCDM-k 2: projected wf
66 : ! Disentanglement
67 : integer:: disentangle_func_type ! 1:unity 2: erfc function 3: gauss function
68 : real(dp):: mu, sigma
69 :
70 : ! Projected Wannier function related
71 : complex(dp), allocatable:: projectors(:, :)
72 :
73 : ! SCDM related
74 : integer, allocatable:: cols(:)
75 : real(dp), allocatable:: anchor_kpt(:)
76 : integer:: anchor_ikpt
77 : integer, allocatable:: anchor_ibands(:)
78 : logical:: project_to_anchor = .False.
79 :
80 : ! Output Wannier function and Hamiltonian
81 : integer:: nwann, nkpt, nband, nbasis, nkdim
82 : integer:: dim ! dimension of position
83 : integer:: nR
84 : integer, allocatable:: Rlist(:,:) !(idim, iRpt)
85 : complex(dp), allocatable:: Amnk(:, :, :) !(nband, nwann, nkpt)
86 : complex(dp), allocatable:: Hwannk(:, :, :) !(nwann, nwann, nkpt)
87 :
88 : complex(dp), allocatable:: psi_wann_k(:, :, :) !(nbasis, nwann, nkpt)
89 :
90 : complex(dp), allocatable:: HwannR(:, :, :) !(nwann, nwann, nR)
91 : complex(dp), allocatable:: wannR(:,:,:) !(nbasis, nwann, nR)
92 :
93 : contains
94 : procedure:: initialize
95 : procedure:: finalize
96 : procedure:: get_psi_k
97 : procedure:: get_evals_k
98 : procedure:: run_all
99 : procedure:: find_kpoint
100 : !procedure:: remove_phase
101 : procedure:: auto_find_anchors
102 : procedure:: get_columns
103 : procedure:: get_scdm_Amnk ! Amnk for all kpoints
104 : procedure:: get_projected_Amnk ! Amnk for all kpoints
105 : procedure:: get_Amnk
106 : procedure:: get_weight
107 : procedure:: set_anchor
108 : procedure:: set_disp_projector
109 : procedure:: set_mode_projector
110 : procedure:: get_wannR_and_HwannR
111 : procedure:: select_columns
112 : procedure:: construct_wannier
113 : procedure:: write_Amnk_w90
114 : procedure:: write_Hwann_w90
115 : procedure:: create_ncfile
116 : procedure:: close_ncfile
117 : procedure:: write_wann_netcdf
118 : procedure:: get_wannier_eigen
119 : procedure:: get_wannier_eigen_klist
120 : end type WannierBuilder_t
121 :
122 :
123 : ! Extends WannierBuilder_t with pointer to eigens.
124 : type, extends(WannierBuilder_t):: WannierBuilder_witheigen_t
125 : real(dp), pointer:: evals(:, :) => null() !(iband, ikpt)
126 : complex(dp), pointer:: psi(:, :, :) => null() ! (ibasis, iband, ikpt)
127 : contains
128 : procedure :: set_eigen => set_eigen
129 : procedure :: get_psi_k => get_psi_k_from_eigen
130 : procedure :: get_evals_k => get_evals_k_from_eigen
131 : end type WannierBuilder_witheigen_t
132 :
133 : contains
134 :
135 : !===============================================================
136 : !
137 : !> @
138 : !> kpts: kpoints. indices: (idim, ikpt)
139 : !> kweights: kweights. indices: (ikpt)
140 : !> nwann: number of Wannier functions to be calcualted.
141 : !> nbasis: number of basis in the original wavefunction.
142 : !> disentangle_func_type: the type of the disentanglement function. 1: unity function. 2. Fermi. 3. Gauss
143 : !> project_to_anchor: whether to multiply the weight function by the projection to the anchor states.
144 : !===============================================================
145 3 : subroutine initialize(self,kpts, kweights, Rlist, nwann, nbasis, nband, &
146 3 : & disentangle_func_type, mu, sigma, exclude_bands, project_to_anchor, method)
147 : class(WannierBuilder_t), intent(inout):: self
148 : integer, intent(in):: nwann, nbasis, nband
149 : real(dp), intent(in):: kpts(:, :) !(idim, ikpt)
150 : real(dp), intent(in):: kweights(:) !(ikpt)
151 : integer, intent(in):: Rlist(:, :) !(idim, iRpt)
152 : integer, optional, intent(in):: disentangle_func_type
153 : real(dp), optional, intent(in):: mu, sigma
154 : integer, optional, intent(in):: exclude_bands(:)
155 : logical, optional, intent(in):: project_to_anchor
156 : integer, intent(in):: method
157 :
158 3 : self%nkdim = size(kpts, 1)
159 3 : self%nkpt = size(kpts, 2)
160 3 : self%nwann = nwann
161 3 : self%nbasis = nbasis
162 3 : self%nband = nband
163 3 : self%method = method
164 : !if (present(psi_phase)) then
165 : ! if (psi_phase) then
166 : ! ABI_MALLOC(self%psi, (self%nbasis, self%nband, self%nkpt))
167 : ! call self%remove_phase(psi)
168 : ! else
169 : ! self%psi => psi
170 : ! end if
171 : !else
172 : ! self%psi => psi
173 : !end if
174 :
175 9 : ABI_MALLOC(self%cols, (self%nwann))
176 12 : self%cols(:) = 0
177 12 : ABI_MALLOC(self%kpts, (self%nkdim, self%nkpt))
178 774 : self%kpts = kpts
179 9 : ABI_MALLOC(self%kweights, (self%nkpt))
180 198 : self%kweights = kweights
181 :
182 3 : self%nR = size(Rlist, 2)
183 12 : ABI_MALLOC(self%Rlist, (self%nkdim, self%nR))
184 774 : self%Rlist = Rlist
185 :
186 : !ABI_MALLOC(self%weight, (self%nband, self%nkpt))
187 : !self%weight(:, :) = 0.0_dp
188 :
189 3 : if (present(disentangle_func_type)) then
190 3 : self%disentangle_func_type = disentangle_func_type
191 : else
192 0 : self%disentangle_func_type = 0
193 : end if
194 :
195 3 : if (present(mu)) then
196 3 : self%mu = mu
197 : else
198 0 : self%mu = 0
199 : end if
200 :
201 3 : if (present(sigma)) then
202 3 : self%sigma = sigma
203 : else
204 0 : self%sigma = sigma
205 : end if
206 :
207 15 : ABI_MALLOC(self%Amnk, (self%nband, self%nwann, self%nkpt))
208 15 : ABI_MALLOC(self%psi_wann_k, (self%nbasis, self%nwann, self%nkpt))
209 15 : ABI_MALLOC(self%Hwannk, (self%nwann, self%nwann, self%nkpt))
210 :
211 3 : if (present(exclude_bands)) then
212 9 : ABI_MALLOC(self%exclude_bands, (size(exclude_bands, 1)))
213 : end if
214 :
215 3 : if (present(project_to_anchor)) self%project_to_anchor = project_to_anchor
216 3 : end subroutine initialize
217 :
218 :
219 :
220 3 : subroutine finalize(self)
221 : class(WannierBuilder_t), intent(inout):: self
222 3 : ABI_SFREE(self%cols)
223 3 : ABI_SFREE(self%kpts)
224 3 : ABI_SFREE(self%kweights)
225 3 : ABI_SFREE(self%Amnk)
226 3 : ABI_SFREE(self%psi_wann_k)
227 3 : ABI_SFREE(self%Hwannk)
228 3 : ABI_SFREE(self%Rlist)
229 3 : ABI_SFREE(self%wannR)
230 3 : ABI_SFREE(self%HwannR)
231 3 : ABI_SFREE(self%exclude_bands)
232 5 : select case (self%method)
233 : case(1)
234 2 : ABI_SFREE(self%anchor_kpt)
235 2 : ABI_SFREE(self%anchor_ibands)
236 2 : ABI_SFREE(self%projectors)
237 : case(2)
238 3 : ABI_SFREE(self%projectors)
239 : end select
240 3 : end subroutine finalize
241 :
242 0 : function get_psi_k(self, ikpt) result(psik)
243 : class(WannierBuilder_t), intent(inout):: self
244 : integer, intent(in):: ikpt
245 : complex(dp), pointer:: psik(:, :)
246 0 : ABI_UNUSED_A(self)
247 0 : ABI_UNUSED_A(ikpt)
248 0 : ABI_UNUSED_A(psik)
249 0 : ABI_ERROR("WannierBuilder_t%get_psi_k should be overrided!")
250 0 : end function get_psi_k
251 :
252 :
253 0 : function get_evals_k(self, ikpt) result(ek)
254 : class(WannierBuilder_t), intent(inout):: self
255 : integer, intent(in):: ikpt
256 : real(dp), pointer:: ek(:)
257 0 : ABI_UNUSED_A(self)
258 0 : ABI_UNUSED_A(ikpt)
259 0 : ABI_UNUSED_A(ek)
260 0 : ABI_ERROR("WannierBuilder_t%get_evals_k should be overrided")
261 0 : end function get_evals_k
262 :
263 :
264 : ! automatically set the anchor points using the weight functions.
265 : ! The bands with the largest weights are selected as the anchor points.
266 0 : subroutine auto_find_anchors(self, ianchors)
267 : class(WannierBuilder_t), intent(inout):: self
268 : integer, intent(out):: ianchors(self%nwann)
269 : integer:: i
270 0 : real(dp):: weights(self%nband)
271 0 : integer:: order(self%nband)
272 :
273 : call self%get_weight(self%anchor_ikpt, self%disentangle_func_type, &
274 0 : & self%mu, self%sigma, weights, project_to_anchor=.False.)
275 0 : call insertion_sort_double(weights, order)
276 :
277 0 : do i = 1, self%nwann
278 0 : ianchors(i)= order(self%nband-i+1)
279 : end do
280 0 : end subroutine auto_find_anchors
281 :
282 2 : subroutine set_anchor(self, anchor_kpt, anchor_ibands)
283 : !> anchor_kpt: anchor kpoint (optional).
284 : !> anchor_ibands: the indices of mode used as anchor points (optional).
285 : class(WannierBuilder_t), intent(inout):: self
286 : real(dp), intent(in) :: anchor_kpt(:)
287 : integer, optional, intent(in):: anchor_ibands(:)
288 2 : complex(dp), pointer :: psik(:,:)
289 : character(len = 500):: msg
290 : integer :: i
291 6 : ABI_MALLOC(self%anchor_ibands, (self%nwann))
292 6 : ABI_MALLOC(self%anchor_kpt, (size(anchor_kpt)))
293 8 : ABI_MALLOC(self%projectors, (self%nbasis, self%nwann))
294 10 : self%anchor_kpt = anchor_kpt
295 2 : self%anchor_ikpt = self%find_kpoint(anchor_kpt)
296 :
297 2 : if (.not. present(anchor_ibands)) then
298 0 : call wrtout( std_out, "Anchor points not specified, finding atomatically")
299 0 : call self%auto_find_anchors( self%anchor_ibands)
300 2 : else if (.not. size(anchor_ibands) == self%nwann) then
301 0 : ABI_ERROR("The number of anchor points should be equal to the number of Wannier functions.")
302 : else
303 10 : self%anchor_ibands = anchor_ibands
304 : end if
305 2 : write(msg, "(2a)") "Anchor point band indices set to ", trim(ltoa(self%anchor_ibands))
306 6 : call wrtout([ab_out, std_out], msg )
307 2 : psik=> self%get_psi_k(self%anchor_ikpt)
308 8 : do i = 1, self%nwann
309 98 : self%projectors(:, i)=psik(:, self%anchor_ibands(i))
310 : end do
311 2 : end subroutine set_anchor
312 :
313 :
314 1 : subroutine set_disp_projector(self, id_projectors)
315 : class(WannierBuilder_t), intent(inout):: self
316 : integer, intent(in):: id_projectors(:)
317 : integer:: i
318 4 : ABI_MALLOC(self%projectors, (self%nbasis, self%nwann))
319 49 : self%projectors(:,:)=zero
320 4 : do i = 1, self%nwann
321 4 : self%projectors(id_projectors(i), i)= cmplx(1.0, 0.0, dp)
322 : end do
323 1 : end subroutine set_disp_projector
324 :
325 0 : subroutine set_mode_projector(self, kpoint, iband)
326 : class(WannierBuilder_t), intent(inout):: self
327 : real(dp), intent(in):: kpoint(:)
328 : integer:: iband(:)
329 0 : ABI_UNUSED_A(self)
330 : ABI_UNUSED(kpoint)
331 : ABI_UNUSED(iband)
332 0 : end subroutine set_mode_projector
333 :
334 :
335 2 : subroutine select_columns(self)
336 : class(WannierBuilder_t), intent(inout):: self
337 : integer:: iband
338 4 : complex(dp):: psi_dagger(self%nband, self%nbasis)
339 4 : complex(dp):: psi_dagger_copy(self%nband, self%nbasis)
340 4 : real(dp):: weight(self%nband)
341 : !real(dp), pointer:: evals_anchor(:)
342 : !type(eigensolver):: esolver
343 : character(len = 500):: msg
344 : ! find anchor points, by default gamma
345 2 : self%anchor_ikpt = self%find_kpoint(self%anchor_kpt)
346 : ! TODO: add qpt if anchor_ikpt is not found
347 : !
348 : !if (size(self%anchor_ibands) /= 0) then
349 : !
350 : !end if
351 : ! calculate weight matrix for each kpoint
352 : call self%get_weight(self%anchor_ikpt, self%disentangle_func_type, self%mu, self%sigma, weight, &
353 2 : &project_to_anchor = .True.)
354 : ! &project_to_anchor = self%project_to_anchor)
355 :
356 : ! at anchor-kpoint, find cols
357 : ! psi: (ibasis, iband)
358 482 : psi_dagger = transpose(conjg(self%get_psi_k(self%anchor_ikpt)))
359 32 : do iband = 1, self%nband
360 482 : psi_dagger(iband, :) = psi_dagger(iband, :)*weight(iband)
361 : end do
362 482 : psi_dagger_copy(:,:) = psi_dagger(:,:)
363 2 : call self%get_columns(psi_dagger_copy, self%cols)
364 2 : write(msg, '(2a) ') 'Columns selected: ', trim(ltoa(self%cols))
365 6 : call wrtout([ab_out, std_out], msg )
366 :
367 : !psi_dagger_copy(:,:) = psi_dagger(:,:)
368 : !! check the eigen values:
369 : !call self%get_Amnk(self%anchor_ikpt, Amn)
370 : !! print the anchor point eigen values:
371 : !evals_anchor => self%get_evals_k(self%anchor_ikpt)
372 : !call Amn_to_H_from_evals(Amn, evals_anchor, &
373 : ! & self%nwann, self%nband, Hwann)
374 : !evals = evals_anchor(self%anchor_ibands)
375 : !write(msg, '(2a)') "The eigen values of the anchor points: ", &
376 : ! & trim(ltoa(evals))
377 : !call wrtout([ab_out, std_out], msg )
378 : !! calculate the eigen values of the Hwannk at anchor point
379 : !call esolver%run(evals, Hwann)
380 : !write(msg, '(2a)') "The eigen values of Hwann(k_anchor): ", &
381 : ! & trim(ltoa(evals))
382 : !call wrtout([ab_out, std_out], msg )
383 : !call esolver%finalize()
384 2 : end subroutine select_columns
385 :
386 3 : subroutine construct_wannier(self)
387 : class(WannierBuilder_t), intent(inout):: self
388 : integer:: ikpt
389 3 : complex(dp), pointer:: p(:, :)
390 : !real(dp):: weight(self%nband)
391 :
392 : !complex(dp):: tmp(self%nwann, self%nwann)
393 : !real(dp):: evals(self%nwann)
394 : !type(eigensolver):: esolver
395 :
396 3 : if(self%method == 1)then
397 2 : call self%select_columns()
398 : end if
399 :
400 : ! For each kpoint, calculate Amn matrix, wannier function, and Hk at k
401 195 : do ikpt = 1, self%nkpt
402 : !Amnk (nband, nwann, nkpt)
403 192 : p => self%get_psi_k(ikpt)
404 192 : call self%get_Amnk(ikpt, self%Amnk(:, :, ikpt))
405 : ! psik*Amnk
406 796416 : self%psi_wann_k(:, :, ikpt) = matmul(p, self%Amnk(:, :, ikpt))
407 : call Amn_to_H_from_evals(self%Amnk(:, :, ikpt), self%get_evals_k(ikpt), &
408 195 : self%nwann, self%nband, self%Hwannk(:, :, ikpt))
409 : !tmp = self%Hwannk(:,:,ikpt)
410 : !call esolver%run(evals, tmp)
411 : !call esolver%finalize()
412 : !print *, "ev1:", self%get_evals_k(ikpt)
413 : ! print *, "ev2:",evals
414 :
415 : end do
416 : ! Fourier transform of wannier function to real space
417 3 : call self%get_wannR_and_HwannR(self%Rlist)
418 3 : end subroutine construct_wannier
419 :
420 :
421 :
422 0 : subroutine run_all(self, ncfilename, Amnkfilename)
423 : class(WannierBuilder_t), intent(inout):: self
424 : character(*), intent(in):: ncfilename
425 : character(*), intent(in):: Amnkfilename
426 : type(IOWannNC):: ncfile
427 0 : call self%construct_wannier()
428 0 : call self%create_ncfile(ncfilename, ncfile)
429 : call self%write_wann_netcdf( ncfile, &
430 0 : &wannR_unit='dimensionless', HwannR_unit='eV')
431 0 : call self%close_ncfile(ncfile)
432 0 : call self%write_Amnk_w90(trim(Amnkfilename))
433 0 : end subroutine run_all
434 :
435 : !subroutine remove_phase(self, psip)
436 : ! class(WannierBuilder_t), intent(inout):: self
437 : ! complex(dp), intent(in):: psip(:, :, :) ! (ibasis, iband, ikpt)
438 : ! !complex(dp), intent(out):: psi(:,:,:) ! (ibasis, iband, ikpt)
439 : ! integer:: ikpt, ibasis
440 : ! complex(dp):: phase
441 : ! do ikpt = 1, self%nkpt
442 : ! do ibasis = 1, self%nbasis
443 : ! phase = exp(-tpi_im*dot_product(self%kpts(:, ikpt), self%positions_red(:, ibasis)))
444 : ! self%psi(ibasis, :, ikpt) = psip(ibasis, :, ikpt)*phase
445 : ! end do
446 : ! end do
447 : !end subroutine remove_phase
448 :
449 : !===============================================================
450 : ! Find one kpoint in a list of kpoints.
451 : !> @
452 : !===============================================================
453 4 : function find_kpoint(self, kpoint) result(ik)
454 : class(WannierBuilder_t), intent(inout):: self
455 : real(dp), intent(in):: kpoint(:)
456 : integer:: ik, nk
457 : integer:: i
458 8 : real(dp):: a(size(self%kpts, 2))
459 4 : nk = size(self%kpts, 2)
460 : ! should transfer back to 1st BZ?
461 260 : do i = 1, nk
462 1028 : a(i) = sum((self%kpts(:, i) - kpoint)**2)
463 : end do
464 :
465 264 : ik = minloc(a, dim = 1)
466 4 : if (a(ik) > 0.001) then
467 0 : ABI_ERROR("Error in finding kpoint from kpoint list. ")
468 : end if
469 4 : end function find_kpoint
470 :
471 : !===============================================================
472 : ! Calculate the weight function for each mode described by iband and ikpt
473 : ! The
474 : !> @
475 : !===============================================================
476 194 : subroutine get_weight(self, ikpt, disentanglement, mu, sigma, weight, project_to_anchor)
477 : class(WannierBuilder_t), intent(inout):: self
478 : integer, intent(in):: ikpt, disentanglement
479 : real(dp), intent(in):: mu, sigma
480 : real(dp), intent(inout):: weight(self%nband)
481 : logical, intent(in):: project_to_anchor
482 :
483 : integer:: iband, ianchor
484 : real(dp):: proj
485 : complex(dp):: p
486 194 : real(dp), pointer:: ek(:)
487 194 : complex(dp), pointer:: psik(:,:)
488 :
489 388 : ek => self%get_evals_k(ikpt)
490 194 : select case (disentanglement)
491 : case (1)
492 1040 : weight(:) = 1.0
493 : case (2)
494 2064 : do iband = 1, self%nband
495 2064 : weight(iband) = fermi(ek(iband), mu, sigma)
496 : end do
497 : case (3)
498 0 : do iband = 1, self%nband
499 0 : weight(iband) = gaussian(ek(iband), mu, sigma)
500 : end do
501 : case default
502 194 : ABI_ERROR("The disentanglement function type can only be 1:unity, 2: fermi, 3: gaussian")
503 : end select
504 :
505 : ! weight_mk *=\sum_anchor < psi_anchor | psi mk>
506 :
507 194 : if( project_to_anchor) then
508 130 : if (size(self%anchor_ibands) /= 0) then
509 130 : psik=>self%get_psi_k(ikpt)
510 2080 : do iband = 1, self%nband
511 1950 : proj = 0.0_dp
512 7800 : do ianchor = 1, size(self%anchor_ibands)
513 93600 : p = dot_product(self%projectors(:, ianchor), psik(:, iband))
514 7800 : proj = proj+real(conjg(p)*p)
515 : end do
516 2080 : weight(iband) = weight(iband)*proj
517 : end do
518 : end if
519 : end if
520 194 : end subroutine get_weight
521 :
522 2 : subroutine get_columns(self, psi_dagger, cols)
523 : class(WannierBuilder_t), intent(inout):: self
524 : complex(dp), intent(in):: psi_dagger(:, :)
525 4 : integer:: piv(size(psi_dagger, 2))
526 : integer, intent(inout):: cols(self%nwann)
527 2 : call complex_QRCP_piv_only(psi_dagger, piv)
528 8 : cols = piv(:self%nwann)
529 2 : end subroutine get_columns
530 :
531 192 : subroutine get_Amnk(self, ikpt, Amnk)
532 : class(WannierBuilder_t), intent(inout):: self
533 : integer, intent(in):: ikpt
534 : complex(dp), intent(inout):: Amnk(self%nband, self%nwann)
535 192 : if(self%method == 1) then
536 128 : call self%get_scdm_Amnk(ikpt, Amnk)
537 64 : else if(self%method == 2) then
538 64 : call self%get_projected_Amnk(ikpt, Amnk)
539 : end if
540 192 : end subroutine get_Amnk
541 :
542 128 : subroutine get_scdm_Amnk(self, ikpt, Amnk)
543 : class(WannierBuilder_t), intent(inout):: self
544 : integer, intent(in):: ikpt
545 256 : complex(dp):: psi_dagger(self%nband, self%nbasis)
546 : complex(dp), intent(inout):: Amnk(self%nband, self%nwann)
547 256 : real(dp):: weight(self%nband)
548 256 : complex(dp):: U(self%nband, self%nwann), VT(self%nwann, self%nwann)
549 256 : real(dp):: S(self%nband)
550 : !real(dp):: weights(self%nband)
551 : integer:: iband
552 128 : complex(dp), pointer:: p(:, :)
553 :
554 : call self%get_weight(ikpt, self%disentangle_func_type, self%mu, self%sigma, weight, &
555 128 : &project_to_anchor = self%project_to_anchor)
556 :
557 128 : p => self%get_psi_k(ikpt)
558 2048 : do iband = 1, self%nband
559 30848 : psi_dagger(iband, :) = conjg(p(:, iband)) *weight(iband)
560 : end do
561 :
562 : ! orthogonalize selected columns
563 6272 : call complex_svd(psi_dagger(:, self%cols), U, S, VT, 'S')
564 25344 : Amnk(:, :) = matmul(U, VT)
565 128 : end subroutine get_scdm_Amnk
566 :
567 :
568 64 : subroutine get_projected_Amnk(self, ikpt, Amnk)
569 : class(WannierBuilder_t), intent(inout):: self
570 : integer, intent(in):: ikpt
571 : complex(dp), intent(inout):: Amnk(self%nband, self%nwann)
572 128 : complex(dp):: U(self%nband, self%nwann), VT(self%nwann, self%nwann)
573 128 : real(dp):: S(self%nband), weights(self%nband)
574 : integer:: iband, iwann
575 64 : complex(dp), pointer:: psi(:, :)
576 :
577 128 : psi => self%get_psi_k(ikpt)
578 : call self%get_weight(ikpt, self%disentangle_func_type, &
579 64 : & self%mu, self%sigma, weights, project_to_anchor=.False.)
580 :
581 : ! <proj||psi> * weight
582 1024 : do iband = 1, self%nband
583 3904 : do iwann = 1, self%nwann
584 : !Amnk(iband, iwann)= dot_product(conjg(self%projectors(:, iwann)), psi(:, iband )) * weights(iband)
585 : !Amnk(iband, iwann)= dot_product(self%projectors(:, iwann), conjg(psi(:, iband ))) * weights(iband)
586 47040 : Amnk(iband, iwann)= dot_product(self%projectors(:, iwann), psi(:, iband )) * weights(iband)
587 : end do
588 : end do
589 64 : call complex_svd(Amnk, U, S, VT, 'S')
590 12672 : Amnk(:, :) = matmul(U, VT)
591 64 : end subroutine get_projected_Amnk
592 :
593 :
594 3 : subroutine get_wannR_and_HwannR(self, Rlist)
595 : class(WannierBuilder_t), intent(inout):: self
596 : integer, intent(in):: Rlist(:, :)
597 : !complex(dp), intent(out):: HR(self%nwann, self%nwann, size(Rlist, 2))
598 : !-- H(R)= \sum_k H(k) * exp(i2pi k.R)
599 : integer:: ik, iR, nR
600 : complex(dp):: factor
601 3 : nR = size(Rlist, 2)
602 15 : ABI_MALLOC(self%HwannR, (self%nwann, self%nwann, nR))
603 15 : ABI_MALLOC(self%WannR, (self%nbasis, self%nwann, nR))
604 :
605 2499 : self%HwannR(:, :, :) = cmplx(0.0, 0.0, dp)
606 9411 : self%wannR(:, :, :) = cmplx(0.0, 0.0, dp)
607 195 : do ik = 1, self%nkpt
608 12483 : do iR = 1, nR
609 49152 : factor = exp(-tpi_Im*dot_product(self%kpts(:, ik), Rlist(:, iR))) * self%kweights(ik)
610 159744 : self%HwannR(:, :, iR) = self%HwannR(:,:, iR) + self%Hwannk(:, :, ik)*factor
611 602304 : self%wannR(:, :, iR) = self%wannR(:,:, iR) + self%psi_wann_k(:, :, ik)*factor
612 : end do
613 : end do
614 3 : end subroutine get_wannR_and_HwannR
615 :
616 192 : subroutine Amn_to_H_from_evals(Amn, evals, nwann, nband, Hwann)
617 : integer, intent(in):: nwann, nband
618 : complex(dp), intent(in):: Amn(nband, nwann)
619 : real(dp), intent(in):: evals(nband)
620 : complex(dp), intent(inout):: Hwann(nwann, nwann)
621 : integer:: i
622 384 : complex(dp):: tmp(nwann, nband)
623 :
624 : ! A\dagger E
625 3072 : do i = 1, nband
626 11712 : tmp(:, i) = conjg(Amn(i, :))*evals(i)
627 : end do
628 : ! Hwann = A\dagger @ E @ A
629 38016 : Hwann = matmul(tmp, Amn)
630 192 : end subroutine Amn_to_H_from_evals
631 :
632 0 : subroutine Amn_to_H(Amn, psi, H0, nbasis, nwann, Hwann)
633 : ! Hwann = psi\dagger A
634 : complex(dp), intent(in):: Amn(:, :), psi(:, :), H0(:, :)
635 : complex(dp), intent(inout):: Hwann(:, :)
636 : integer, intent(in):: nbasis, nwann
637 0 : complex(dp):: tmp(nbasis, nwann)
638 : !Hwann = A_dagger@psi_dagger@H0@psi@A
639 0 : tmp(:, :) = matmul(psi, Amn)
640 0 : Hwann = matmul(matmul(transpose(conjg(tmp)), H0), tmp)
641 0 : end subroutine Amn_to_H
642 :
643 0 : subroutine write_Amnk_w90(self, fname)
644 : ! write to Amnk file
645 : class(WannierBuilder_t), intent(inout):: self
646 : character(len=*), intent(in):: fname
647 : integer:: iwann, iband, ikpt, locibnd
648 : integer:: iun_amn
649 : character(len=500):: msg
650 :
651 0 : if (open_file(trim(fname)//".amn", msg, newunit=iun_amn, &
652 : & form="formatted", status="unknown", action="write") /= 0) then
653 0 : ABI_ERROR(msg)
654 : end if
655 :
656 :
657 : !IF (wan_mode=='standalone') THEN
658 : ! iun_amn = find_free_unit()
659 : ! IF (ionode) OPEN (unit = iun_amn, file = trim(seedname)//".amn",form='formatted')
660 : !ENDIF
661 :
662 : !TODO: re-enable this.
663 : !WRITE(stdout, '(a, i8)') ' AMN: iknum = ',iknum
664 : !
665 : !IF (wan_mode=='standalone') THEN
666 : ! CALL date_and_tim( cdate, ctime )
667 : ! header='Created on '//cdate//' at '//ctime//' with SCDM '
668 : ! IF (ionode) THEN
669 : ! WRITE (iun_amn, *) header
670 : ! WRITE (iun_amn, '(3i8, xxx, 2f10.6)') numbands, iknum, n_wannier, scdm_mu, scdm_sigma
671 : ! ENDIF
672 : !ENDIF
673 :
674 0 : do ikpt = 1, self%nkpt
675 0 : do iwann = 1, self%nwann
676 0 : locibnd = 0
677 0 : do iband = 1, self%nband
678 : !IF (excluded_band(iband)) CYCLE
679 0 : locibnd = locibnd+1
680 0 : WRITE (iun_amn, '(3i5, 2f18.12)') locibnd, iwann, ikpt, &
681 0 : & REAL(self%Amnk(locibnd, iwann, ikpt)), &
682 0 : & AIMAG(self%Amnk(locibnd, iwann, ikpt))
683 : end do
684 : end do
685 : end do
686 0 : close (iun_amn)
687 0 : end subroutine write_Amnk_w90
688 :
689 0 : subroutine write_Hwann_w90(self, HR, Rlist, fname)
690 : class(WannierBuilder_t), intent(inout):: self
691 : complex(dp), intent(in):: HR(:, :, :)
692 : integer, intent(in):: Rlist(:, :)
693 : character(len=*), intent(in):: fname
694 : integer:: iR, ifile, iwann1, iwann2
695 : character(len=500):: msg
696 :
697 0 : if (open_file(trim(fname)//".hr", msg, newunit=ifile, &
698 : & form="formatted", status="unknown", action="write") /= 0) then
699 0 : ABI_ERROR(msg)
700 : end if
701 :
702 :
703 0 : do iR = 1, size(Rlist, 2)
704 0 : WRITE (ifile, '(3i5)') Rlist(:, iR)
705 0 : do iwann1 = 1, self%nwann
706 0 : do iwann2 = 1, self%nwann
707 0 : WRITE (ifile, '(f18.12)') HR(iwann1, iwann2, iR)
708 : end do
709 : end do
710 : end do
711 0 : close (ifile)
712 0 : end subroutine write_Hwann_w90
713 :
714 3 : subroutine create_ncfile(self, fname, ncfile)
715 : class(WannierBuilder_t), intent(inout):: self
716 : type(IOWannNC):: ncfile
717 : character(len=*), intent(in):: fname
718 3 : ABI_UNUSED_A(self)
719 3 : call ncfile%initialize(filename = fname)
720 3 : end subroutine create_ncfile
721 :
722 3 : subroutine close_ncfile(self, ncfile)
723 : class(WannierBuilder_t), intent(inout):: self
724 : type(IOWannNC):: ncfile
725 3 : ABI_UNUSED_A(self)
726 3 : call ncfile%close_file()
727 3 : end subroutine close_ncfile
728 :
729 :
730 3 : subroutine write_wann_netcdf(self, ncfile, wannR_unit, HwannR_unit)
731 : class(WannierBuilder_t), intent(inout):: self
732 : character(*), intent(in):: HwannR_unit, wannR_unit
733 : type(IOWannNC), intent(inout):: ncfile
734 : call ncfile%write_wann( nR = self%nR, ndim = self%nkdim, &
735 : & nwann = self%nwann, nbasis = self%nbasis, Rlist = self%Rlist, &
736 : & wannR = self%wannR, HwannR = self%HwannR, &
737 3 : & wannR_unit = wannR_unit, HwannR_unit = HwannR_unit)
738 : call ncfile%write_Amnk(nkpt = self%nkpt, nband = self%nband, nwann = self%nwann, &
739 3 : & kpoints = self%kpts, Amnk = self%Amnk)
740 : !TODO: add write_eigenvalues
741 3 : end subroutine write_wann_netcdf
742 :
743 344 : subroutine get_wannier_eigen(self, kpoint, evals, evecs)
744 : class(WannierBuilder_t), intent(inout):: self
745 : real(dp), intent(in) :: kpoint(3)
746 : real(dp), intent(inout) :: evals(self%nwann)
747 : complex(dp), optional, intent(inout) :: evecs(self%nwann, self%nwann)
748 688 : complex(dp) :: Hk(self%nwann, self%nwann), phase
749 344 : type(eigensolver):: esolver
750 : integer :: iR
751 4472 : Hk(:,:)=0.0_dp
752 22360 : do iR=1, self%nR
753 88064 : phase = exp(tpi_im * dot_product(kpoint, self%Rlist(:, iR)))
754 286552 : Hk = Hk + self%HwannR(:, :, iR) * phase
755 : end do
756 344 : call esolver%run(evals, Hk)
757 : ! Hk is overwritten as evecs
758 344 : if (present(evecs)) then
759 4472 : evecs=Hk
760 : end if
761 344 : call esolver%finalize()
762 688 : end subroutine get_wannier_eigen
763 :
764 2 : subroutine get_wannier_eigen_klist(self, kpoints, nk, evals_nk, evecs_nk)
765 : class(WannierBuilder_t), intent(inout):: self
766 : integer, intent(in) :: nk
767 : real(dp), intent(in) :: kpoints(3, nk)
768 : real(dp), intent(inout) :: evals_nk(self%nwann, nk)
769 : complex(dp), optional, intent(inout) :: evecs_nk(self%nwann, self%nwann, nk)
770 : integer :: ik
771 346 : do ik =1, nk
772 346 : if (present(evecs_nk)) then
773 : call self%get_wannier_eigen(kpoints(:, ik), &
774 344 : & evals_nk(:, ik), evecs_nk(:,:, ik))
775 : else
776 0 : call self%get_wannier_eigen(kpoints(:, ik), evals_nk(:, ik))
777 : end if
778 : end do
779 2 : end subroutine get_wannier_eigen_klist
780 :
781 :
782 : !============================ WannierBuilder_witheigen_t =========================
783 :
784 3 : subroutine set_eigen(self, evals, psi)
785 : class(WannierBuilder_witheigen_t) :: self
786 : real(dp), intent(in), target:: evals(:, :) !(iband, ikpt)
787 : complex(dp), intent(in), target:: psi(:, :, :) ! (ibasis, iband, ikpt)
788 3 : self%psi => psi
789 3 : self%evals => evals
790 3 : end subroutine set_eigen
791 :
792 386 : function get_evals_k_from_eigen(self, ikpt) result(ek)
793 : class(WannierBuilder_witheigen_t), intent(inout):: self
794 : integer, intent(in):: ikpt
795 : real(dp), pointer:: ek(:)
796 386 : ek => self%evals( :, ikpt)
797 386 : end function get_evals_k_from_eigen
798 :
799 :
800 518 : function get_psi_k_from_eigen(self, ikpt) result(psik)
801 : class(WannierBuilder_witheigen_t), intent(inout):: self
802 : integer, intent(in):: ikpt
803 : complex(dp), pointer:: psik(:, :)
804 518 : psik => self%psi(:, :, ikpt)
805 518 : end function get_psi_k_from_eigen
806 :
807 :
808 0 : end module m_wannier_builder
809 : !!***
|