Octopus
wannier_calc.F90
Go to the documentation of this file.
1!! Copyright (C) 2017-2019 H. Huebener, N. Tancogne-Dejean
2!! Copyright (C) 2026 A. Buccheri, J. Reimann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
24 use, intrinsic :: iso_fortran_env
25
27 use comm_oct_m
28 use debug_oct_m
30 use global_oct_m
32 use io_oct_m
34 use ions_oct_m
37 use mesh_oct_m
40 use mpi_oct_m
46 use space_oct_m
51 use types_oct_m
52 use unit_oct_m
55 use wfs_elec_oct_m, only: wfs_elec_t
57
58 implicit none
59 private
60
61 public :: &
76
82 integer :: l, m, s
83 integer :: radial = 1
84 real(real64) :: site(3)
85 real(real64) :: s_qaxis(3) = [0.0_real64, 0.0_real64, 1.0_real64]
86 real(real64) :: z(3) = [0.0_real64, 0.0_real64, 1.0_real64]
87 real(real64) :: x(3) = [1.0_real64, 0.0_real64, 0.0_real64]
88 real(real64) :: zona = 1.0_real64
89 end type wannier_calc_proj_t
90
91contains
92
97 subroutine wannier_calc_load_restart(namespace, mc, space, st, gr, kpoints, restart_states)
98 type(namespace_t), intent(in) :: namespace
99 type(multicomm_t), intent(in) :: mc
100 class(space_t), intent(inout) :: space
101 type(states_elec_t), intent(inout) :: st
102 class(mesh_t), intent(inout) :: gr
103 type(kpoints_t), intent(inout) :: kpoints
104 integer, optional, intent(in) :: restart_states ! RESTART_GS or RESTART_TD
105 ! Defaults to ground state
106
107 integer :: restart_states_, ierr, nik, dim, nst
108 type(restart_t) :: restart
109
110 restart_states_ = optional_default(restart_states, restart_gs)
111 if (.not. (restart_states_ == restart_gs .or. restart_states_ == restart_td)) then
112 message(1) = 'Invalid restart_states value; expected RESTART_GS or RESTART_TD.'
113 call messages_fatal(1)
114 end if
115
116 call states_elec_allocate_wfns(st, gr, wfs_type = type_cmplx)
117 call restart%init(namespace, restart_states_, restart_type_load, mc, ierr, gr)
119 if (ierr /= 0) then
120 write(message(1),'(a)') 'Error opening restart file'
121 call messages_fatal(1)
122 endif
123
124 call states_elec_look(restart, nik, dim, nst, ierr)
125 if (st%d%ispin == spin_polarized) nik = nik / 2
126 if (dim /= st%d%dim) then
127 write(message(1),'(a)') 'Restart structure not commensurate, since spin dimensions differ.'
128 call messages_fatal(1)
129 else if (nik /= kpoints%reduced%npoints) then
130 write(message(1),'(a)') 'Restart structure not commensurate, since number of k-points differ.'
131 call messages_fatal(1)
132 else if (nst /= st%nst) then
133 write(message(1),'(a)') 'Restart structure not commensurate, since number of states differ.'
134 call messages_fatal(1)
135 end if
136
137 call states_elec_load(restart, namespace, space, st, gr, kpoints, fixed_occ=st%restart_fixed_occ , &
138 ierr=ierr, label = ": wannier90")
139 call restart%end()
140
141 end subroutine wannier_calc_load_restart
142
143 ! TODO: Removed SCDM - Should reintroduce once the code is working
149 subroutine wannier_calc_create_amn(wan_opts, &
150 band_index, space, mesh, latt, st, kpoints, &
151 spin_channel, num_proj, proj_input, projection)
152 type(wannier_opts_t), intent(in) :: wan_opts
153 class(space_t), intent(in) :: space
154 class(mesh_t), intent(in) :: mesh
155 type(lattice_vectors_t), intent(in) :: latt
156 type(states_elec_t), intent(in) :: st
157 type(kpoints_t), intent(in) :: kpoints
158 integer, contiguous, intent(in) :: band_index(:)
159 integer, intent(in) :: spin_channel
160 integer, intent(in) :: num_proj
161 type(wannier_calc_proj_t), contiguous, intent(in) :: proj_input(:)
162
163 complex(real64), contiguous, intent(out) :: projection(:, :, :)
164
165 integer :: ist, ik, idim, iw, ip, ik_real, iband, num_kpts
166 real(real64) :: center(3), kpoint(3)
167
168 complex(real64), allocatable :: psi(:,:), phase(:)
169 real(real64), allocatable :: ylm(:)
170 type(orbitalset_t), allocatable :: orbitals(:)
171
173 call profiling_in("W90_AMN")
174
175 if (st%parallel_in_states) then
176 call messages_not_implemented("w90_amn output with states parallelization")
177 end if
179 message(1) = "Info: Computing the projection matrix"
182 assert(num_proj == size(proj_input))
184 num_kpts = kpoints%full%npoints
185
186 ! Precompute orbitals
187 safe_allocate(orbitals(1:num_proj))
188 do iw=1, num_proj
189 call orbitalset_init(orbitals(iw))
190
191 orbitals(iw)%norbs = 1
192 orbitals(iw)%ndim = 1
193 orbitals(iw)%radius = -log(wan_opts%threshold)
194 orbitals(iw)%use_submesh = .false.
195
196 ! cartesian coordinate of orbital center
197 center(1:3) = latt%red_to_cart(proj_input(iw)%site(1:3))
198 call submesh_init(orbitals(iw)%sphere, space, mesh, latt, center, orbitals(iw)%radius)
199
200 ! get dorb as submesh points
201 safe_allocate(ylm(1:orbitals(iw)%sphere%np))
202 ! (this is a routine from pwscf)
203 call ylm_wannier(ylm, proj_input(iw)%l, proj_input(iw)%m, &
204 orbitals(iw)%sphere%r, orbitals(iw)%sphere%rel_x, orbitals(iw)%sphere%np)
205
206 if (proj_input(iw)%radial /= 1) then
207 call messages_not_implemented("oct-wannier90: r/=1 for the radial part")
208 end if
209
210 ! apply radial function
211 do ip = 1, orbitals(iw)%sphere%np
212 ylm(ip) = ylm(ip) * m_two * exp(-orbitals(iw)%sphere%r(ip))
213 end do
214
215 ! NOTE(Alex) One can probably fill directly into zorb, and avoid allocating ylm
216 safe_allocate(orbitals(iw)%zorb(1:orbitals(iw)%sphere%np, 1:1, 1:1))
217 orbitals(iw)%zorb(1:orbitals(iw)%sphere%np, 1, 1) = ylm(1:orbitals(iw)%sphere%np)
218 safe_deallocate_a(ylm)
219
220 safe_allocate(orbitals(iw)%phase(1:orbitals(iw)%sphere%np, st%d%kpt%start:st%d%kpt%end))
221 orbitals(iw)%phase = m_z0
222 safe_allocate(orbitals(iw)%eorb_mesh(1:mesh%np, 1:1, 1:1, st%d%kpt%start:st%d%kpt%end))
223 orbitals(iw)%eorb_mesh = m_z0
224
225 call orbitalset_update_phase(orbitals(iw), space%dim, st%d%kpt, kpoints, st%d%ispin == spin_polarized, &
226 kpt_max = num_kpts)
227 end do
228
229 ! Compute the projections
230 safe_allocate(psi(1:mesh%np, 1:st%d%dim))
231 safe_allocate(phase(1:mesh%np))
232 projection = m_zero
233
234 do ik = 1, num_kpts
235 kpoint(1:space%dim) = kpoints%get_point(ik)
236 do ip = 1, mesh%np
237 phase(ip) = exp(-m_zi * sum(mesh%x(1:space%dim, ip) * kpoint(1:space%dim)))
238 end do
239
240 ik_real = st%d%get_k_spin_index(ik, spin_channel)
241
242 ! TODO(Alex) ist and iw loops need interchanging to optimise array access
243 do ist = 1, size(band_index)
244 iband = band_index(ist)
245
246 if(ik_real >= st%d%kpt%start .and. ik_real <= st%d%kpt%end) then
247 call states_elec_get_state(st, mesh, iband, ik_real, psi)
248
249 do idim = 1, st%d%dim
250 do ip = 1, mesh%np
251 psi(ip, idim) = psi(ip, idim)*phase(ip)
252 end do
253 end do
254
255 do iw = 1, num_proj
256 idim = 1
257 if (wan_opts%spinors) idim = wan_opts%spin_proj_component(iw)
258 !At the moment the orbitals do not depend on idim
259 !The idim index for eorb_mesh would be for a spin-resolved orbital like j=1/2
260 projection(iband, iw, ik) = zmf_dotp(mesh, psi(1:mesh%np, idim), &
261 orbitals(iw)%eorb_mesh(1:mesh%np, 1, 1, ik_real), reduce = .false.)
262 end do
263
264 call profiling_in("W90_AMN_REDUCE")
265 call mesh%allreduce(projection(ist, :, ik))
266 call profiling_out("W90_AMN_REDUCE")
267 end if
268
269 if(st%d%kpt%parallel) then
270 call comm_allreduce(st%d%kpt%mpi_grp, projection(ist, :, ik))
271 end if
272
273 end do !ist
274 end do !ik
275
276 safe_deallocate_a(psi)
277 safe_deallocate_a(phase)
278
279 do iw = 1, num_proj
280 call orbitalset_end(orbitals(iw))
281 end do
282 safe_deallocate_a(orbitals)
283
284 call profiling_out("W90_AMN")
285
287
288 end subroutine wannier_calc_create_amn
289
299 subroutine wannier_calc_create_mmn(band_index, mesh, st, latt, &
300 spin_channel, nnlist, nncell, overlap)
301 integer, contiguous, intent(in) :: band_index(:)
302 class(mesh_t), intent(in) :: mesh
303 type(states_elec_t), target, intent(in) :: st
304 type(lattice_vectors_t), intent(in) :: latt ! can differ from ions%latt for non-periodic systems
305 integer, intent(in) :: spin_channel
306 integer, contiguous, intent(in) :: nnlist(:,:)
307 integer, contiguous, intent(in) :: nncell(:,:,:)
308
309 complex(real64), contiguous, intent(out) :: overlap(:, :, :, :) ! distributed in k-points
310
311 integer :: ist, jst, ik, ip, iknn, idim, ibind
312 integer :: ik_oct, iknn_oct, inn
313 integer :: ik_loc
314 integer :: iband, jband, inode, node_fr, node_to
315 real(real64) :: gcart(3)
316 integer :: g(3)
317
318 integer :: nntot, num_kpts
319
320 complex(real64), allocatable :: psim(:,:), psin(:,:), phase(:)
321 type(wfs_elec_t), pointer :: batch
322 type(mpi_request) :: send_req
323
325
326 call profiling_in("W90_MMN")
327
328
329 nntot = size(nnlist, 2)
330 num_kpts = size(nnlist, 1)
331 assert(size(nnlist, 1) == num_kpts)
332 assert(size(nncell, 1) == 3)
333 assert(size(nncell, 2) == num_kpts)
334 assert(size(nncell, 3) == nntot)
335
336 if (st%parallel_in_states) then
337 call messages_not_implemented("w90_mmn output with states parallelization")
338 end if
339
340 message(1) = "Info: Computing the overlap matrix for wannierisation"
341 call messages_info(1)
342
343 overlap = m_zero
344 safe_allocate(psim(1:mesh%np, 1:st%d%dim))
345 safe_allocate(psin(1:mesh%np, 1:st%d%dim))
346 safe_allocate(phase(1:mesh%np))
347
348 ! overlap is distributed in k like wannier90''s m_matrix_local
349 ik_loc = 0
350
351 ! loop over the pairs specified in the nnk tuple
352 do ik = 1, num_kpts
353 ik_oct = st%d%get_k_spin_index(ik, spin_channel)
354 if (ik_oct >= st%d%kpt%start .and. ik_oct <= st%d%kpt%end) ik_loc = ik_loc + 1
355
356 do inn = 1, nntot
357
358 iknn = nnlist(ik, inn)
359 g(1:3) = nncell(:, ik, inn)
360 iknn_oct = st%d%get_k_spin_index(iknn, spin_channel)
361
362 ! If the k-point is local, compute the phase e^{-i G.r}
363 if(ik_oct >= st%d%kpt%start .and. ik_oct <= st%d%kpt%end) then
364 ! Wannier90 treats everything fully periodic
365 ! Conversion is done with the 3D "correct" klattice
366 call kpoints_to_absolute(latt, real(g, real64) , gcart)
367
368 ! Phase that gives u_{n,k+G}(r) from u_{nk}(r)
369 ! Here the minus sign of Octopus cancels with minus sign of the input G
370 ! (ik and iknn correspond in the list to minus the k-points in Octopus)
371 if (any(g /= 0)) then
372 do ip = 1, mesh%np
373 phase(ip) = exp(-m_zi*dot_product(mesh%x(1:3, ip), gcart(1:3)))
374 end do
375 end if
376 end if
377
378 ! Loop over distributed bands
379 do jst = 1, size(band_index)
380 jband = band_index(jst)
381
382 if (st%d%kpt%parallel) then
383 node_fr = -1
384 node_to = -1
385 do inode = 0, st%d%kpt%mpi_grp%size-1
386 if(iknn_oct >= st%st_kpt_task(inode,3) .and. iknn_oct <= st%st_kpt_task(inode,4)) then
387 node_fr = inode
388 end if
389 if(ik_oct >= st%st_kpt_task(inode,3) .and. ik_oct <= st%st_kpt_task(inode,4)) then
390 node_to = inode
391 end if
392 end do
393 assert(node_fr > -1)
394 assert(node_to > -1)
395 send_req = mpi_request_null
396 ! We have locally the k-point
397 if (state_kpt_is_local(st, jband, iknn_oct)) then
398 call states_elec_get_state(st, mesh, jband, iknn_oct, psin)
399 ! We send it only if we don`t want to use it locally
400 if(node_to /= st%d%kpt%mpi_grp%rank) then
401 call st%d%kpt%mpi_grp%isend(psin, mesh%np*st%d%dim, mpi_double_complex, node_to, send_req)
402 end if
403 end if
404 ! We receive the desired state, only if it is not a local one
405 if(node_to == st%d%kpt%mpi_grp%rank .and. node_to /= node_fr) then
406 call st%d%kpt%mpi_grp%recv(psin, mesh%np*st%d%dim, mpi_double_complex, node_fr)
407 end if
408 if (send_req /= mpi_request_null) then
409 call st%d%kpt%mpi_grp%wait(send_req)
410 end if
411 else
412 call states_elec_get_state(st, mesh, jband, iknn_oct, psin)
413 end if
414
415 if(ik_oct >= st%d%kpt%start .and. ik_oct <= st%d%kpt%end) then
416
417 ! Do not apply the phase if the phase factor is 1
418 if (any(g /= 0)) then
419 do idim = 1, st%d%dim
420 do ip = 1, mesh%np
421 psin(ip, idim) = psin(ip, idim) * phase(ip)
422 end do
423 end do
424 end if
425
426 ! See Eq. (25) in PRB 56, 12847 (1997)
427 ! Loop over local k-points
428 do iband = 1, size(band_index)
429 ist = band_index(iband)
430
431 batch => st%group%psib(st%group%iblock(ist), ik_oct)
432
433 select case (batch%status())
434 case (batch_not_packed)
435 overlap(iband, jst, inn, ik_loc) = m_z0
436 do idim = 1, st%d%dim
437 ibind = batch%inv_index((/ist, idim/))
438 overlap(iband, jst, inn, ik_loc) = overlap(iband, jst, inn, ik_loc) + &
439 zmf_dotp(mesh, batch%zff_linear(:, ibind), psin(:,idim), reduce = .false.)
440 end do
441 !Not properly done at the moment
443 call states_elec_get_state(st, mesh, ist, ik_oct, psim)
444 overlap(iband, jst, inn, ik_loc) = zmf_dotp(mesh, st%d%dim, psim, psin, reduce = .false.)
445 end select
446 end do !iband
447
448 call profiling_in("W90_MMN_REDUCE")
449 call mesh%allreduce(overlap(:, jst, inn, ik_loc))
450 call profiling_out("W90_MMN_REDUCE")
451 end if
452 end do !jst
453 end do !inn
454 end do !ik
455
456 assert(ik_loc == size(overlap, 4))
457
458 safe_deallocate_a(psim)
459 safe_deallocate_a(psin)
460 safe_deallocate_a(phase)
461
462 call profiling_out("W90_MMN")
463
465
466 end subroutine wannier_calc_create_mmn
467
472 subroutine wannier_calc_read_centers(wan_opts, centers)
473 type(wannier_opts_t), intent(in) :: wan_opts
474 real(real64), contiguous, intent(inout) :: centers(:, :)
475
476 integer :: w90_xyz, iw
477 character(len=2) :: dum
478 logical :: exist
479
481
482 assert(size(centers, 2) == wan_opts%num_wann)
483 assert(size(centers, 1) == 3)
484
485 inquire(file=trim(adjustl(wan_opts%prefix))//'_centres.xyz',exist=exist)
486 if (.not. exist) then
487 message(1) = 'Cannot find the Wannier90 file seedname_centres.xyz.'
488 call messages_fatal(1)
489 end if
490
491 w90_xyz = io_open(trim(adjustl(wan_opts%prefix))//'_centres.xyz', global_namespace, action='read')
492
493 !Skip two lines
494 read(w90_xyz, *)
495 read(w90_xyz, *)
496 do iw = 1, wan_opts%num_wann
497 read(w90_xyz, *) dum, centers(1:3, iw)
498 ! Wannier90 outputs the coordinates in angstrom
499 centers(1:3, iw) = units_to_atomic(unit_angstrom, centers(1:3, iw))
500 end do
501 call io_close(w90_xyz)
502
504 end subroutine wannier_calc_read_centers
505
510 subroutine wannier_calc_read_u_matrices(wan_opts, kpoints, u_matrix, u_dis_matrix)
511 type(wannier_opts_t), intent(in) :: wan_opts
512 type(kpoints_t), intent(in) :: kpoints
513 complex(real64), contiguous, intent(inout) :: u_matrix(:, :, :)
514 complex(real64), contiguous, intent(inout) :: u_dis_matrix(:, :, :)
515
516 integer :: w90_u_mat, w90_u_dis, ik, ib, iw, iw2, nik, nwann, nib
517 integer :: num_kpts
518 logical :: exist, have_disentangled
519
520 num_kpts = product(kpoints%nik_axis(1:3))
521
523
524 inquire(file=trim(adjustl(wan_opts%prefix))//'_u.mat',exist=exist)
525 if (.not. exist) then
526 message(1) = 'Cannot find the Wannier90 seedname_u.mat file.'
527 call messages_fatal(1)
528 end if
529 w90_u_mat = io_open(trim(adjustl(wan_opts%prefix))//'_u.mat', global_namespace, action='read')
530
531 !Skip one line
532 read(w90_u_mat, *)
533 !Read num_kpts, num_wann, num_wann for consistency check
534 read(w90_u_mat, *) nik, nwann, nwann
535 if (nik /= num_kpts .or. nwann /= wan_opts%num_wann) then
536 message(1) = "The U matrix has inconsistent shape."
537 call messages_fatal(1)
538 end if
539
540 do ik = 1, num_kpts
541 !Skip one line
542 read(w90_u_mat, *)
543 !Skip one line (k-point coordinate)
544 read(w90_u_mat, *)
545 read(w90_u_mat, '(f15.10,sp,f15.10)') ((u_matrix(iw, iw2, ik), iw=1, wan_opts%num_wann), iw2=1, wan_opts%num_wann)
546 end do
547
548 call io_close(w90_u_mat)
549
550 inquire(file=trim(adjustl(wan_opts%prefix))//'_u_dis.mat',exist=have_disentangled)
551 if (have_disentangled) then
552 ! Read u_dis.mat: dimensions are (w90_num_bands x w90_num_wann) per k-point.
553 ! The band rows follow the compressed, non-excluded band ordering used by
554 ! the rest of the Wannier90 interface (i.e. after applying exclude_bands).
555 w90_u_dis = io_open(trim(adjustl(wan_opts%prefix))//'_u_dis.mat', global_namespace, action='read')
556 !Skip one line
557 read(w90_u_dis, *)
558 !Read num_kpts, num_wann, num_bands for consistency check
559 read(w90_u_dis, *) nik, nwann, nib
560 if (nik /= num_kpts .or. nwann /= wan_opts%num_wann .or. nib /= wan_opts%num_bands) then
561 message(1) = 'The u_dis matrix has inconsistent shape.'
562 call messages_fatal(1)
563 end if
564
565 do ik = 1, num_kpts
566 !Skip one line
567 read(w90_u_dis, *)
568 !Skip one line (k-point coordinate)
569 read(w90_u_dis, *)
570 read(w90_u_dis, '(f15.10,sp,f15.10)') ((u_dis_matrix(ib, iw, ik), ib=1, wan_opts%num_bands), iw=1, wan_opts%num_wann)
571 end do
572
573 call io_close(w90_u_dis)
574
575 ! In case of disentanglement, u_dis matrix needs to be reordered to the correct layout.
576 ! See issue #1465.
577 end if
578
580 end subroutine wannier_calc_read_u_matrices
581
585 subroutine wannier_calc_get_header(header_start, header)
586 character(len=*), intent(in) :: header_start
587 character(len=*), intent(out) :: header
588
589 integer :: date_time(8)
590
592
593 call date_and_time(values=date_time)
594 write(header, '(a,i4,a1,i2.2,a1,i2.2,a,i2.2,a1,i2.2,a1,i2.2)') &
595 header_start, date_time(1), '/', date_time(2), '/', date_time(3), &
596 ' at ', date_time(5), ':', date_time(6), ':', date_time(7)
597
599 end subroutine wannier_calc_get_header
600
604 subroutine wannier_calc_write_centers(dir, prefix, centers, ions)
605 character(len=*), intent(in) :: dir
606 character(len=*), intent(in) :: prefix
607 real(real64), intent(in) :: centers(:, :)
608 class(ions_t), intent(in) :: ions
609
610 integer :: w90_xyz, iw, ia, ind
611 character(len=512) :: header
612
614
615 w90_xyz = io_open(trim(adjustl(dir))//'/'//trim(adjustl(prefix))//'_centres.xyz', global_namespace, action='write', die=.false.)
616 if (w90_xyz == -1) then
617 message(1) = 'Unable to open output file '//trim(adjustl(prefix))//'_centres.xyz for writing.'
618 call messages_fatal(1)
619 end if
620
621 write(w90_xyz, '(i6)') size(centers, 2) + ions%natoms
622 call wannier_calc_get_header('Wannier centers, written by octopus on ', header)
623 write (w90_xyz, *) trim(header)
624
625 do iw = 1, size(centers, 2)
626 write(w90_xyz, '("X",6x,3(f14.8,3x))') &
627 (units_from_atomic(unit_angstrom, centers(ind, iw)), ind=1, 3)
628 end do
629 do ia = 1, ions%natoms
630 write(w90_xyz, '(a2,5x,3(f14.8,3x))') trim(ions%atom(ia)%label), &
631 (units_from_atomic(unit_angstrom, ions%pos(ind, ia)), ind=1, 3)
632 end do
633 call io_close(w90_xyz)
634
636
637 end subroutine wannier_calc_write_centers
638
643 subroutine wannier_calc_write_u_matrices(dir, prefix, kpoints, u_matrix, u_dis_matrix)
644 character(len=*), intent(in) :: dir
645 character(len=*), intent(in) :: prefix
646 type(kpoints_t), intent(in) :: kpoints
647 complex(real64), contiguous, intent(in) :: u_matrix(:, :, :)
648 complex(real64), contiguous, intent(in) :: u_dis_matrix(:, :, :)
649
650 integer :: w90_u_mat, w90_u_dis
651 logical :: have_disentangled
652 integer :: i, j, nkp, num_wann, num_bands, num_kpts
653 character(len=512) :: header
654
655 num_kpts = size(u_matrix, 3)
656 num_wann = size(u_matrix, 1)
657 num_bands = size(u_dis_matrix, 1)
658 assert(num_kpts == size(kpoints%reduced%red_point, 2))
659
661
662 call wannier_calc_get_header('written on ', header)
663
664 w90_u_mat = io_open(trim(adjustl(dir))//'/'//trim(adjustl(prefix))//'_u.mat', global_namespace, action='write', die=.false.)
665 if (w90_u_mat == -1) then
666 message(1) = 'Unable to open output file '//trim(adjustl(prefix))//'_u.mat for writing.'
667 call messages_fatal(1)
668 end if
669
670 write (w90_u_mat, *) trim(header)
671 write (w90_u_mat, *) num_kpts, num_wann, num_wann
672
673 do nkp = 1, num_kpts
674 write (w90_u_mat, *)
675 write (w90_u_mat, '(f15.10,sp,f15.10,sp,f15.10)') -kpoints%reduced%red_point(1:3, nkp)
676 write (w90_u_mat, '(f15.10,sp,f15.10)') ((u_matrix(i, j, nkp), i=1, num_wann), j=1, num_wann)
677 end do
678
679 call io_close(w90_u_mat)
681 inquire(file=trim(trim(adjustl(prefix))//'_u_dis.mat'),exist=have_disentangled)
682 if (have_disentangled) then
683
684 w90_u_dis = io_open(trim(adjustl(dir))//'/'//trim(adjustl(prefix))//'_u_dis.mat', &
685 global_namespace, action='write', die=.false.)
686 if (w90_u_dis == -1) then
687 message(1) = 'Unable to open output file '//trim(adjustl(prefix))//'_u_dis.mat for writing.'
688 call messages_fatal(1)
689 end if
690
691 write (w90_u_dis, *) trim(header)
692 write (w90_u_dis, *) num_kpts, num_wann, num_bands
693 do nkp = 1, num_kpts
694 write (w90_u_dis, *)
695 write (w90_u_dis, '(f15.10,sp,f15.10,sp,f15.10)') -kpoints%reduced%red_point(1:3, nkp)
696 write (w90_u_dis, '(f15.10,sp,f15.10)') ((u_dis_matrix(i, j, nkp), i=1, num_bands), j=1, num_wann)
697 end do
698
699 call io_close(w90_u_dis)
700 end if
701
703
704 end subroutine wannier_calc_write_u_matrices
705
707 subroutine wannier_calc_write_spreads(dir, prefix, spreads)
708 character(len=*), intent(in) :: dir
709 character(len=*), intent(in) :: prefix
710 real(real64), intent(in) :: spreads(:)
711
712 integer :: w90_xyz, iw
713 character(len=512) :: header
714
716
717 w90_xyz = io_open(trim(adjustl(dir))//'/'//trim(adjustl(prefix))//'_spreads.xyz', global_namespace, action='write', die=.false.)
718 if (w90_xyz == -1) then
719 message(1) = 'Unable to open output file '//trim(adjustl(prefix))//'_spreads.xyz for writing.'
720 call messages_fatal(1)
721 end if
722
723 call wannier_calc_get_header('Wannier spreads, written by octopus on ', header)
724 write (w90_xyz, *) trim(header)
725
726 do iw = 1, size(spreads, 1)
727 write(w90_xyz, '("X",6x,f14.8)') spreads(iw) * units_from_atomic(unit_angstrom, 1.0_real64)**2
728 end do
729 call io_close(w90_xyz)
730
732
733 end subroutine wannier_calc_write_spreads
734
740 subroutine wannier_calc_write_hr_file(dir, prefix, irvec, ndegen, ham_r)
741 character(len=*), intent(in) :: dir
742 character(len=*), intent(in) :: prefix
743 integer, contiguous, intent(in) :: irvec(:, :)
744 integer, contiguous, intent(in) :: ndegen(:)
745 complex(real64), contiguous, intent(in) :: ham_r(:, :, :)
746
747 integer :: w90_hr_dat
748 integer :: i, j, irpt
749 character(len=512) :: header
750 integer :: nrpts, n_wannier
751
753
754 nrpts = size(ham_r, 3)
755 n_wannier = size(ham_r, 1)
756 assert(size(irvec, 2) == nrpts)
757 assert(size(ndegen, 1) == nrpts)
758
759 w90_hr_dat = io_open(trim(adjustl(dir))//'/'//trim(adjustl(prefix))//'_hr.dat', global_namespace, action='write', die=.false.)
760 if (w90_hr_dat == -1) then
761 message(1) = 'Unable to open output file '//trim(adjustl(prefix))//'_hr.dat for writing.'
762 call messages_fatal(1)
763 end if
764
765 call wannier_calc_get_header('written on ', header)
766 write (w90_hr_dat, *) trim(header)
767
768 write (w90_hr_dat, *) size(ham_r, 1)
769 write (w90_hr_dat, *) nrpts
770 write (w90_hr_dat, '(15I5)') (ndegen(i), i=1, nrpts)
771 do irpt = 1, nrpts
772 do i = 1, n_wannier
773 do j = 1, n_wannier
774 write (w90_hr_dat, '(5I5,2F12.6)') irvec(:, irpt), j, i, &
775 units_from_atomic(unit_ev, ham_r(j, i, irpt))
776 end do
777 end do
778 end do
779
780 call io_close(w90_hr_dat)
781
783 end subroutine wannier_calc_write_hr_file
784
786 logical function wannier_calc_r_in_wigner_seitz_cell(rvec, real_metric, mp_grid, ws_search_size, &
787 ws_distance_tol, ndegen) result(in_cell)
788 integer, intent(in) :: rvec(3)
789 real(real64), intent(in) :: real_metric(3, 3)
790 integer, intent(in) :: mp_grid(3)
791 integer, intent(in) :: ws_search_size(3)
792 real(real64), intent(in) :: ws_distance_tol
793 integer, optional, intent(out) :: ndegen
794
795 integer :: i1, i2, i3, icnt
796 integer :: ndiff(3)
797 real(real64) :: dist_min, dist_to_origin
798 real(real64) :: dist(product(2*ws_search_size + 3))
799
800 ! no push_sub, called too frequently
801
802 ! Squared distances from rvec to all superlattice points within the search range
803 icnt = 0
804 do i1 = -ws_search_size(1) - 1, ws_search_size(1) + 1
805 do i2 = -ws_search_size(2) - 1, ws_search_size(2) + 1
806 do i3 = -ws_search_size(3) - 1, ws_search_size(3) + 1
807 icnt = icnt + 1
808 ndiff = rvec - [i1, i2, i3] * mp_grid
809 dist(icnt) = dot_product(real(ndiff, real64), matmul(real_metric, real(ndiff, real64)))
810 end do
811 end do
812 end do
813
814 dist_to_origin = dot_product(real(rvec, real64), matmul(real_metric, real(rvec, real64)))
815 dist_min = minval(dist)
816
817 in_cell = abs(dist_to_origin - dist_min) < ws_distance_tol**2
818 if (present(ndegen)) ndegen = count(abs(dist - dist_min) < ws_distance_tol**2)
819
821
826 subroutine wannier_calc_wigner_seitz_count(real_lattice, mp_grid, ws_search_size, ws_distance_tol, nrpts)
827 real(real64), intent(in) :: real_lattice(3,3)
828 integer, intent(in) :: mp_grid(3)
829 integer, intent(in) :: ws_search_size(3)
830 real(real64), intent(in) :: ws_distance_tol
831 integer, intent(out) :: nrpts
832
833 integer :: n1, n2, n3
834 real(real64) :: real_metric(3, 3)
837
838 real_metric = matmul(transpose(real_lattice), real_lattice)
839
840 nrpts = 0
841 do n1 = -ws_search_size(1)*mp_grid(1), ws_search_size(1)*mp_grid(1)
842 do n2 = -ws_search_size(2)*mp_grid(2), ws_search_size(2)*mp_grid(2)
843 do n3 = -ws_search_size(3)*mp_grid(3), ws_search_size(3)*mp_grid(3)
844 if (wannier_calc_r_in_wigner_seitz_cell([n1, n2, n3], real_metric, mp_grid, &
845 ws_search_size, ws_distance_tol)) then
846 nrpts = nrpts + 1
847 end if
848 end do
849 end do
850 end do
851
854
859 subroutine wannier_calc_wigner_seitz_fill(real_lattice, mp_grid, ws_search_size, ws_distance_tol, &
860 nrpts, irvec, ndegen)
861 real(real64), intent(in) :: real_lattice(3,3)
862 integer, intent(in) :: mp_grid(3)
863 integer, intent(in) :: ws_search_size(3)
864 real(real64), intent(in) :: ws_distance_tol
865 integer, intent(in) :: nrpts
866 integer, intent(out) :: irvec(3, nrpts)
867 integer, intent(out) :: ndegen(nrpts)
868
869 integer :: n1, n2, n3, irpt, ndeg
870 real(real64) :: real_metric(3, 3)
871
873
874 real_metric = matmul(transpose(real_lattice), real_lattice)
875
876 irpt = 0
877 do n1 = -ws_search_size(1)*mp_grid(1), ws_search_size(1)*mp_grid(1)
878 do n2 = -ws_search_size(2)*mp_grid(2), ws_search_size(2)*mp_grid(2)
879 do n3 = -ws_search_size(3)*mp_grid(3), ws_search_size(3)*mp_grid(3)
880 if (wannier_calc_r_in_wigner_seitz_cell([n1, n2, n3], real_metric, mp_grid, &
881 ws_search_size, ws_distance_tol, ndeg)) then
882 irpt = irpt + 1
883 irvec(:, irpt) = [n1, n2, n3]
884 ndegen(irpt) = ndeg
885 end if
886 end do
887 end do
888 end do
889 assert(irpt == nrpts)
890
891 ! Sum rule from wannier90: the R-points weighted by their inverse degeneracy
892 ! must add up to the number of k-points
893 if (abs(sum(m_one/ndegen) - product(mp_grid)) > 1e-8_real64) then
894 message(1) = "Error computing the Wigner-Seitz points."
895 call messages_fatal(1)
896 end if
897
899 end subroutine wannier_calc_wigner_seitz_fill
900
907 subroutine wannier_calc_update_phase(band_index, st, dt, phase)
908 integer, contiguous, intent(in) :: band_index(:)
909 type(states_elec_t), intent(in) :: st
910 real(real64), intent(in) :: dt
911 complex(real64), contiguous, intent(inout) :: phase(:,:)
912
913 integer :: ik, ist
914
916
917 do ik = 1, size(phase, 2)
918 do ist = 1, size(band_index)
919 phase(ist, ik) = phase(ist, ik) * exp(m_zi * st%eigenval(band_index(ist), ik) * dt)
920 end do
921 end do
922
924 end subroutine wannier_calc_update_phase
925
933 subroutine wannier_calc_compute_ham_r(namespace, mesh, st, hm, kpoints, wannier_opts, &
934 u_matrix, irvec, ham_r)
935 type(namespace_t), intent(in) :: namespace
936 class(mesh_t), intent(in) :: mesh
937 type(states_elec_t), target, intent(inout) :: st
938 type(hamiltonian_elec_t), intent(in) :: hm
939 type(kpoints_t), intent(in) :: kpoints
940 type(wannier_opts_t), intent(in) :: wannier_opts
941 complex(real64), contiguous, intent(in) :: u_matrix(:, :, :)
942 integer, contiguous, intent(in) :: irvec(:, :)
943 complex(real64), contiguous, intent(out) :: ham_r(:, :, :)
944
945 integer :: nk, nrpts, ik, irpt, iq, ikl
946 real(real64) :: rdotk
947 complex(real64), allocatable :: hmss(:, :), ham_k_local(:, :, :)
948
950
951 nk = kpoints%full%npoints
952 nrpts = size(ham_r, 3)
953
954 safe_allocate(hmss(1:wannier_opts%num_bands, 1:wannier_opts%num_bands))
955 safe_allocate(ham_k_local(1:wannier_opts%num_wann, 1:wannier_opts%num_wann, 1:st%d%kpt%nlocal()))
956
957 assert(wannier_opts%num_bands == st%nst)
958 if (wannier_opts%num_bands /= wannier_opts%num_wann) then
959 call messages_not_implemented('TD Wannier: num_bands unequal num_wann', namespace)
960 end if
961
962 ! Hamiltonian matrix elements in the subspace of the (time-dependent) KS states,
963 ! rotated into the Wannier basis: H_W(k) = U(k)^dagger eps(k) U(k)
964 ! Computed once per local k-point and cached
965 do iq = st%d%kpt%start, st%d%kpt%end
966 ik = st%d%get_kpoint_index(iq)
967 ikl = iq - st%d%kpt%start + 1
968 call zsubspace_diag_hamiltonian(namespace, mesh, st, hm, iq, hmss)
969 ham_k_local(:, :, ikl) = matmul(transpose(conjg(u_matrix(:, :, ik))), matmul(hmss, u_matrix(:, :, ik)))
970 end do
971
972 ! Adapted from Wannier90: Fourier transform to real space: H(R) = (1/N_k) sum_k exp(-i k.R) H_W(k)
973 ! Each rank sums only its own local k-points
974 ham_r = m_z0
975 do irpt = 1, nrpts
976 do iq = st%d%kpt%start, st%d%kpt%end
977 ik = st%d%get_kpoint_index(iq)
978 ikl = iq - st%d%kpt%start + 1
979 rdotk = m_two*m_pi*dot_product(kpoints%reduced%red_point(1:3, ik), real(irvec(1:3, irpt), real64))
980 ham_r(:, :, irpt) = ham_r(:, :, irpt) + (exp(m_zi*rdotk)/real(nk, real64)) * ham_k_local(:, :, ikl)
981 ! sign mismatch here because of mismatch in k-point convention between Octopus and Wannier90
982 end do
983 end do
984
985 if (st%d%kpt%parallel) then
986 call comm_allreduce(st%d%kpt%mpi_grp, ham_r)
987 end if
988
989 safe_deallocate_a(hmss)
990 safe_deallocate_a(ham_k_local)
991
993 end subroutine wannier_calc_compute_ham_r
994
995end module wannier_calc_oct_m
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
This module implements batches of mesh functions.
Definition: batch.F90:135
integer, parameter, public batch_not_packed
functions are stored in CPU memory, unpacked order
Definition: batch.F90:311
integer, parameter, public batch_device_packed
functions are stored in device memory in packed order
Definition: batch.F90:311
integer, parameter, public batch_packed
functions are stored in CPU memory, in transposed (packed) order
Definition: batch.F90:311
integer, parameter, public spin_polarized
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
complex(real64), parameter, public m_z0
Definition: global.F90:210
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public m_one
Definition: global.F90:201
subroutine, public write_standard_xyz_file(namespace, fname, pos, species, header)
Write a standard xyz file with atom labels and positions (in Angstrom).
Definition: io.F90:116
subroutine, public io_close(iunit, grp)
Definition: io.F90:467
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:402
subroutine, public kpoints_to_absolute(latt, kin, kout)
Definition: kpoints.F90:1145
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1068
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
type(namespace_t), public global_namespace
Definition: namespace.F90:135
subroutine, public orbitalset_init(this)
Definition: orbitalset.F90:209
subroutine, public orbitalset_end(this)
Definition: orbitalset.F90:235
subroutine, public orbitalset_update_phase(os, dim, kpt, kpoints, spin_polarized, vec_pot, vec_pot_var, kpt_max)
Build the phase correction to the global phase in case the orbital crosses the border of the simulato...
Definition: orbitalset.F90:285
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:631
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:554
integer, parameter, public restart_gs
Definition: restart.F90:156
integer, parameter, public restart_td
Definition: restart.F90:156
integer, parameter, public restart_type_load
Definition: restart.F90:184
logical function, public state_kpt_is_local(st, ist, ik)
check whether a given state (ist, ik) is on the local node
subroutine, public states_elec_allocate_wfns(st, mesh, wfs_type, skip, packed)
Allocates the KS wavefunctions defined within a states_elec_t structure.
subroutine, public states_elec_look(restart, nik, dim, nst, ierr)
Reads the 'states' file in the restart directory, and finds out the nik, dim, and nst contained in it...
This module handles reading and writing restart information for the states_elec_t.
subroutine, public states_elec_load(restart, namespace, space, st, mesh, kpoints, fixed_occ, ierr, iter, lr, lowest_missing, label, verbose, skip)
returns in ierr: <0 => Fatal error, or nothing read =0 => read all wavefunctions >0 => could only rea...
subroutine, public submesh_init(this, space, mesh, latt, center, rc)
Definition: submesh.F90:226
subroutine, public zsubspace_diag_hamiltonian(namespace, mesh, st, hm, ik, hmss, overlap)
Diagonalises the Hamiltonian in the subspace defined by the states.
Definition: subspace.F90:946
type(type_t), parameter, public type_cmplx
Definition: types.F90:137
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
This module defines the unit system, used for input and output.
type(unit_t), public unit_angstrom
For XYZ files.
type(unit_t), public unit_ev
For output energies in eV.
Wannier90 related calculations.
subroutine, public wannier_calc_write_centers(dir, prefix, centers, ions)
Write wannier centers to file.
subroutine, public wannier_calc_wigner_seitz_fill(real_lattice, mp_grid, ws_search_size, ws_distance_tol, nrpts, irvec, ndegen)
Calculate coordinates and degeneracies of R-points in the Wigner-Seitz cell.
subroutine, public wannier_calc_read_centers(wan_opts, centers)
Read wannier centers.
subroutine, public wannier_calc_wigner_seitz_count(real_lattice, mp_grid, ws_search_size, ws_distance_tol, nrpts)
Count the number of R-points in the Wigner-Seitz cell.
subroutine, public wannier_calc_write_hr_file(dir, prefix, irvec, ndegen, ham_r)
Write H(R) in the Wannier basis to a _hr.dat file.
subroutine, public wannier_calc_update_phase(band_index, st, dt, phase)
Accumulate the phase picked up by the KS states in TD run.
subroutine, public wannier_calc_write_u_matrices(dir, prefix, kpoints, u_matrix, u_dis_matrix)
Write U and U_dis matrices to file.
subroutine, public wannier_calc_create_amn(wan_opts, band_index, space, mesh, latt, st, kpoints, spin_channel, num_proj, proj_input, projection)
Calculation of Wannier90 Projection Matrix.
logical function wannier_calc_r_in_wigner_seitz_cell(rvec, real_metric, mp_grid, ws_search_size, ws_distance_tol, ndegen)
Check whether a lattice point lies in the Wigner-Seitz cell of the superlattice.
subroutine, public wannier_calc_create_mmn(band_index, mesh, st, latt, spin_channel, nnlist, nncell, overlap)
Kohn-Sham State Overlap Matrix.
subroutine, public wannier_calc_read_u_matrices(wan_opts, kpoints, u_matrix, u_dis_matrix)
Read wannier transformation matrix.
subroutine wannier_calc_get_header(header_start, header)
Build a file header containing the current date and time.
subroutine, public wannier_calc_compute_ham_r(namespace, mesh, st, hm, kpoints, wannier_opts, u_matrix, irvec, ham_r)
Compute the time-dependent Hamiltonian in the Wannier basis in real space.
subroutine, public wannier_calc_write_spreads(dir, prefix, spreads)
Write wannier spreads to file.
subroutine, public wannier_calc_load_restart(namespace, mc, space, st, gr, kpoints, restart_states)
Load Octopus restart data from disk.
Wannier options module.
subroutine, public ylm_wannier(ylm, l, mr, rr, xx, nr)
Describes mesh distribution to nodes.
Definition: mesh.F90:187
The states_elec_t class contains all electronic wave functions.
Mocks the projection type from wannier90.
Wannier related options.
batches of electronic states
Definition: wfs_elec.F90:143