Octopus
wannier.F90
Go to the documentation of this file.
1!! Copyright (C) 2026 A. Buccheri, J. Reimann
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
25module wannier_oct_m
26 use, intrinsic :: iso_fortran_env
27
28 use debug_oct_m
29 use global_oct_m
32 use io_oct_m
33 use ions_oct_m
36 use mesh_oct_m
38 use mpi_oct_m
42 use parser_oct_m
45 use space_oct_m
48 use types_oct_m
49 use unit_oct_m
54
55#ifdef HAVE_WANNIER90
56 use w90_library
58 only: &
62#endif
63
64 implicit none
65 private
66
67 public :: wannier_t
69 type :: wannier_t
70 type(wannier_opts_t) :: options
71 type(lattice_vectors_t) :: latt
72 complex(real64), allocatable :: u_matrix(:,:,:)
73 complex(real64), allocatable :: u_dis_matrix(:,:,:)
74 real(real64), allocatable :: centers(:,:)
75 real(real64), allocatable :: spreads(:)
76 complex(real64), allocatable :: m_matrix(:,:,:,:)
77 complex(real64), allocatable :: ham_r(:, : ,:)
78 integer, allocatable :: irvec(:, :)
79 integer, allocatable :: ndegen(:)
80 integer :: last_iter = 0
81#ifdef HAVE_WANNIER90
82 type(lib_common_type) :: w90main
83#endif
84
85 contains
86 procedure :: init_from_input => wannier_init_from_input
87 procedure :: init_parallelization => wannier_init_parallelization
88 procedure :: init_data_from_file => wannier_init_data_from_file
89 procedure :: restart_write_data => wannier_restart_write_data
90 procedure :: restart_read_data => wannier_restart_read_data
91 procedure :: write_iter => wannier_write_iter
92 procedure :: update_matrices => wannier_update_matrices
93 final :: wannier_finalize
94 end type wannier_t
95
96contains
97
101 subroutine wannier_init_from_input(this, namespace, kpoints, ions, space, st, gr)
102 class(wannier_t), intent(inout) :: this
103 type(namespace_t), intent(in) :: namespace
104 type(kpoints_t), intent(in) :: kpoints
105 type(ions_t), intent(in) :: ions
106 class(space_t), intent(in) :: space
107 type(states_elec_t), intent(in) :: st
108 class(mesh_t), intent(in) :: gr
109
110 integer :: nrpts
111
113
114 ! Parse all Wannier related options
115 call this%options%parse_oct(namespace)
116 if (this%options%td_method == td_wannier_method_none) then
117 ! No TD wannier functionality requested
119 return
120 end if
121
122#ifndef HAVE_WANNIER90
123 message(1) = 'Octopus was not compiled with support for the Wannier90 library,'
124 message(2) = 'which is required for TDWannierMethod /= none.'
125 call messages_fatal(2, namespace=namespace)
126#endif
127
128 call this%options%parse_win()
129 ! Currently TD Wannier is not supported for the disentanglement case
130 if (this%options%num_bands /= this%options%num_wann) then
131 call messages_not_implemented('TD Wannier: num_bands not equal num_wann')
132 end if
133 ! also not for spin polarized or spinors
134 if (st%d%ispin /= unpolarized) then
135 call messages_not_implemented('TD Wannier: spin polarized and spinors')
136 end if
137 ! and only for 3D systems
138 if (space%dim /= 3) then ! see issue #1466
139 call messages_not_implemented("TD wannier: dimensionality other than 3D")
140 end if
141 ! wannierization is not supported for k-point symmetries
142 if (kpoints%use_symmetries .eqv. .true.) then
143 call messages_not_implemented("TD wannier: k-point symmetries")
144 end if
145 ! nst /= num_bands can occur without excluded bands
146 if (this%options%num_bands /= st%nst) then
147 call messages_not_implemented("TD wannier: Setting nst /= num_bands to exclude bands")
148 end if
149
150 ! Build the effective lattice used for all TD Wannier geometry, and return in this%latt
151 call wannier_build_effective_lattice(ions, space, gr, this%latt)
152
153 safe_allocate(this%u_matrix(1:this%options%num_wann, 1:this%options%num_wann, 1:kpoints%full%npoints))
154 safe_allocate(this%u_dis_matrix(1:this%options%num_bands, 1:this%options%num_wann, 1:kpoints%full%npoints))
155 safe_allocate(this%centers(1:3, 1:this%options%num_wann))
156 safe_allocate(this%spreads(1:this%options%num_wann))
157 this%u_matrix = m_zero
158 this%u_dis_matrix = m_zero
159 this%centers = m_zero
160 this%spreads = m_zero
162 !Initialize translation vectors needed for calculation of H(R) in Wannier basis
163 nrpts = 1
164 call wannier_calc_wigner_seitz_count(this%latt%rlattice, kpoints%nik_axis(1:3), &
165 this%options%ws_search_size, this%options%ws_distance_tol, nrpts)
166 safe_allocate(this%irvec(1:3, 1:nrpts))
167 safe_allocate(this%ndegen(1:nrpts))
168 call wannier_calc_wigner_seitz_fill(this%latt%rlattice, kpoints%nik_axis(1:3), &
169 this%options%ws_search_size, this%options%ws_distance_tol, nrpts, this%irvec, this%ndegen)
170 safe_allocate(this%ham_r(1:this%options%num_wann, 1:this%options%num_wann, 1:nrpts))
171 this%ham_r = m_zero
183 subroutine wannier_build_effective_lattice(ions, space, gr, latt)
184 type(ions_t), intent(in) :: ions
185 class(space_t), intent(in) :: space
186 class(mesh_t), intent(in) :: gr
187 type(lattice_vectors_t), intent(out) :: latt
188
189 real(real64) :: factor(space%dim)
190 integer :: idir
191
193
194 call latt%copy(ions%latt)
195
196 factor = m_one
197 do idir = space%periodic_dim + 1, space%dim
198 factor(idir) = m_two * gr%box%bounding_box_l(idir)
199 end do
200 call latt%scale(factor)
201
204
210 subroutine wannier_init_parallelization(this, namespace, st, ions, kpoints)
211 class(wannier_t), intent(inout) :: this
212 type(namespace_t), intent(in) :: namespace
213 type(states_elec_t), intent(in) :: st
214 type(ions_t), intent(in) :: ions
215 type(kpoints_t), intent(in) :: kpoints
216
217#ifdef HAVE_WANNIER90
218 integer :: ierr, nn, iband, ist, nk_local
219#endif
220
222
223 if (this%options%td_method == td_wannier_method_none) then
225 return
226 end if
227
228#ifdef HAVE_WANNIER90
229 !Initialize wannier90 library object, including kpoint parallelization
230 call wannier90lib_init_w90main(namespace, ions, this%latt, kpoints, st, &
231 this%options, this%w90main, stdout, stderr, ierr)
232 if (ierr /= 0) then
233 write(message(1),'(a,i0)') 'Error initializing wannier90 library object: ', ierr
234 call messages_fatal(1)
235 end if
236
237 ! Suppress all disk IO from wannier90 side. The needed output is controlled within octopus
238 this%w90main%output_file = output_file_type() ! resets all file output to false
239
240 ! Phase mode: wannier90 only evaluates centers and spreads of the phase-evolved U
241 if (this%options%td_method == td_wannier_method_phase) this%w90main%wann_control%num_iter = 0
242
243 ! allocation of m_matrix is done here, since nn HAS to be known (which comes from wannier90 after initialization)
244 ! m_matrix is distributed in k, matching wannier90''s m_matrix_local
245 call w90_get_nn(this%w90main, nn, stdout, stderr, ierr)
246 nk_local = st%d%kpt%nlocal()
247 if (st%d%ispin == spin_polarized) nk_local = nk_local / 2
248 safe_allocate(this%m_matrix(1:this%options%num_bands, 1:this%options%num_bands, 1:nn, 1:nk_local))
249
250 ! Update exclude_list and band_index based on wannier90 input from .win file (if any)
251 safe_allocate(this%options%exclude_list(1:st%nst))
252 this%options%exclude_list = .false.
253 if (allocated(this%w90main%exclude_bands)) then
254 do iband = 1, size(this%w90main%exclude_bands)
255 ist = this%w90main%exclude_bands(iband)
256 this%options%exclude_list(ist) = .true.
257 end do
258 end if
259 ! Currently TD Wannier is not supported for exclude_band case
260 if (any(this%options%exclude_list)) then
261 call messages_not_implemented('TD Wannier: exclude_bands')
262 end if
263 this%options%band_index = pack([(ist, ist=1,st%nst)], this%options%exclude_list .eqv. .false.)
264#endif
265
267
268 end subroutine wannier_init_parallelization
274 subroutine wannier_init_data_from_file(this, kpoints)
275 class(wannier_t), intent(inout) :: this
276 type(kpoints_t), intent(in) :: kpoints
277
279
280 if (this%options%td_method == td_wannier_method_none) then
282 return
283 end if
284
285 call wannier_calc_read_centers(this%options, this%centers)
286 call wannier_calc_read_u_matrices(this%options, kpoints, this%u_matrix, this%u_dis_matrix)
287#ifdef HAVE_WANNIER90
288 call wannier90lib_initialize_matrix_data(this%w90main, this%u_matrix, &
289 this%u_dis_matrix, this%m_matrix, this%centers)
290#endif
291
293 end subroutine wannier_init_data_from_file
294
299 subroutine wannier_restart_write_data(this, namespace, mc, gr)
300 class(wannier_t), intent(inout) :: this
301 type(namespace_t), intent(in) :: namespace
302 type(multicomm_t), intent(in) :: mc
303 class(mesh_t), intent(in) :: gr
304
305 type(restart_t) :: restart
306 integer :: ierr
307
309
310 if (this%options%td_method == td_wannier_method_none) then
312 return
313 end if
314
315 call restart%init(namespace, restart_td, restart_type_dump, mc, ierr, mesh=gr)
316 if (ierr /= 0) then
317 message(1) = 'Unable to initialize TD restart for Wannier write.'
318 call messages_fatal(1)
319 end if
320
321 call restart%write_binary('wannier_u_matrix', size(this%u_matrix), this%u_matrix, ierr)
322 if (ierr /= 0) then
323 message(1) = 'Unable to write Wannier restart data (u_matrix).'
324 call messages_fatal(1)
325 end if
326
327 call restart%write_binary('wannier_u_dis_matrix', size(this%u_dis_matrix), this%u_dis_matrix, ierr)
328 if (ierr /= 0) then
329 message(1) = 'Unable to write Wannier restart data (u_dis_matrix).'
330 call messages_fatal(1)
331 end if
332
333 call restart%write_binary('wannier_centers', size(this%centers), this%centers, ierr)
334 if (ierr /= 0) then
335 message(1) = 'Unable to write Wannier restart data (centers).'
336 call messages_fatal(1)
337 end if
338
339 call restart%end()
340
342 end subroutine wannier_restart_write_data
343
348 subroutine wannier_restart_read_data(this, namespace, mc, gr)
349 class(wannier_t), intent(inout) :: this
350 type(namespace_t), intent(in) :: namespace
351 type(multicomm_t), intent(in) :: mc
352 class(mesh_t), intent(in) :: gr
353
354 type(restart_t) :: restart
355 integer :: ierr
356
358
359 if (this%options%td_method == td_wannier_method_none) then
361 return
362 end if
363
364 call restart%init(namespace, restart_td, restart_type_load, mc, ierr, mesh=gr)
365 if (ierr /= 0) then
366 message(1) = 'Unable to initialize TD restart for Wannier read.'
367 call messages_fatal(1)
368 end if
369
370 call restart%read_binary('wannier_u_matrix', size(this%u_matrix), this%u_matrix, ierr)
371 if (ierr /= 0) then
372 message(1) = 'Unable to read Wannier restart data (u_matrix).'
373 call messages_fatal(1)
374 end if
375
376 call restart%read_binary('wannier_u_dis_matrix', size(this%u_dis_matrix), this%u_dis_matrix, ierr)
377 if (ierr /= 0) then
378 message(1) = 'Unable to read Wannier restart data (u_dis_matrix).'
379 call messages_fatal(1)
380 end if
381
382 call restart%read_binary('wannier_centers', size(this%centers), this%centers, ierr)
383 if (ierr /= 0) then
384 message(1) = 'Unable to read Wannier restart data (centers).'
385 call messages_fatal(1)
386 end if
387
388#ifdef HAVE_WANNIER90
389 call wannier90lib_initialize_matrix_data(this%w90main, this%u_matrix, &
390 this%u_dis_matrix, this%m_matrix, this%centers)
391#endif
392
393 call restart%end()
394
397
399 subroutine wannier_write_iter(this, namespace, outp, ions, kpoints)
400 class(wannier_t), intent(in) :: this
401 type(namespace_t), intent(in) :: namespace
402 type(output_t), intent(inout) :: outp
403 class(ions_t), intent(in) :: ions
404 type(kpoints_t), intent(in) :: kpoints
405
406 character(len=MAX_PATH_LEN) :: dir, raw_dir
407
408 push_sub(wannier_write_iter)
409
410 if (this%options%td_method == td_wannier_method_none) then
411 pop_sub(wannier_write_iter)
412 return
413 end if
414
415 ! Only write wannier90 output every n iterations, as specified in input
416 ! This must always coincide with the update, since there is only one variable for both update and output interval.
417 if (mod(this%last_iter, this%options%td_update_interval) == 0) then
418 write(dir, '(a,a,i7.7)') trim(outp%iter_dir),"td.", this%last_iter
419 raw_dir = io_workpath(trim(dir), namespace)
420
421 call io_mkdir(trim(dir), namespace, parents=.true.)
422
423 call wannier_calc_write_u_matrices(trim(raw_dir), trim(this%options%prefix), kpoints, this%u_matrix, this%u_dis_matrix)
424 call wannier_calc_write_centers(trim(raw_dir), trim(this%options%prefix), this%centers, ions)
425 call wannier_calc_write_spreads(trim(raw_dir), trim(this%options%prefix), this%spreads)
426 if (this%options%td_write_hr) then
427 call wannier_calc_write_hr_file(trim(raw_dir), trim(this%options%prefix), this%irvec, this%ndegen, this%ham_r)
428 end if
429 end if
430
431 pop_sub(wannier_write_iter)
432 end subroutine wannier_write_iter
433
435 subroutine wannier_update_matrices(this, iter, namespace, gr, space, st, kpoints, hm, dt)
436 class(wannier_t), intent(inout) :: this
437 integer, intent(in) :: iter
438 type(namespace_t), intent(in) :: namespace
439 class(mesh_t), intent(in) :: gr
440 class(space_t), intent(in) :: space
441 type(states_elec_t), intent(inout) :: st ! inout because calculation of H(R) requires it
442 type(kpoints_t), intent(in) :: kpoints
443 type(hamiltonian_elec_t), intent(in) :: hm
444 real(real64), intent(in) :: dt
445
446 integer :: iw, ik
447 complex(real64) :: phase_step(this%options%num_bands)
448
450
451 if (this%options%td_method == td_wannier_method_none) then
453 return
454 end if
455
456 ! Keep track of iteration for which the update was performed
457 this%last_iter = iter
458
459 ! Accumulate the phase picked up by the KS states in TD run
460 !
461 ! Equation (4) of Phys. Rev. Research 7, 023312 .
462 ! A stationary state would acquire a phase
463 ! \f$ \psi_n(t+\Delta t) = \e^{-i \eps_n \Delta t} \psi_n(t) \f$
464 ! in time.
465 do ik = 1, kpoints%full%npoints
466 phase_step = exp(m_zi * st%eigenval(this%options%band_index, ik) * dt)
467 do iw = 1, this%options%num_wann
468 this%u_matrix(:, iw, ik) = phase_step * this%u_matrix(:, iw, ik)
469 end do
470 end do
471
472 if (mod(iter, this%options%td_update_interval) /= 0) then
474 return
475 end if
476
477 select case (this%options%td_method)
479#ifdef HAVE_WANNIER90
480 ! Brute-force wannierization of TD KS states by calling libwannier90
481 call wannier90lib_wannierization(this%w90main, gr, space, st, this%latt, kpoints, &
482 this%options, this%options%band_index)
484 ! Convert units and fold the centers into the unit cell
485 do iw = 1, size(this%centers, 2)
486 this%centers(1:3, iw) = units_to_atomic(unit_angstrom, this%w90main%wannier_data%centres(1:3, iw))
487 this%centers(1:3, iw) = this%latt%fold_into_cell(this%centers(1:3, iw)) !using minimum-image convention
488 end do
489
490 !Update the spreads
491 this%spreads = this%w90main%wannier_data%spreads * units_to_atomic(unit_angstrom, 1.0_real64)**2
492#endif
493 case default
494 ! Do nothing
495 end select
496
497 !Update lattice model
498 if (this%options%td_write_hr) then
499 call wannier_calc_compute_ham_r(namespace, gr, st, hm, kpoints, this%options, &
500 this%u_matrix, this%irvec, this%ham_r)
501 end if
502
504 end subroutine wannier_update_matrices
505
507 subroutine wannier_finalize(wan)
508 type(wannier_t), intent(inout) :: wan
509
510 push_sub(wannier_finalize)
511
512 if (wan%options%td_method == td_wannier_method_none) then
513 pop_sub(wannier_finalize)
514 return
515 end if
516
517 safe_deallocate_a(wan%m_matrix)
518 safe_deallocate_a(wan%u_matrix)
519 safe_deallocate_a(wan%u_dis_matrix)
520 safe_deallocate_a(wan%centers)
521 safe_deallocate_a(wan%spreads)
522 safe_deallocate_a(wan%ham_r)
523 safe_deallocate_a(wan%irvec)
524 safe_deallocate_a(wan%ndegen)
525
526#ifdef HAVE_WANNIER90
527 ! Currently parsing exclude_bands from .win is only supported
528 ! when using libwannier90
529 safe_deallocate_a(wan%options%exclude_list)
530 safe_deallocate_a(wan%options%band_index)
531#endif
532
533 ! Attributes of `lib_common_type` are just pointers to memory we own, so no additional finalisation required
534
535 pop_sub(wannier_finalize)
536 end subroutine wannier_finalize
537
538end module wannier_oct_m
double exp(double __x) __attribute__((__nothrow__
integer, parameter, public unpolarized
Parameters...
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
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public m_one
Definition: global.F90:201
Definition: io.F90:116
character(len=max_path_len) function, public io_workpath(path, namespace)
construct path name from given name and namespace
Definition: io.F90:318
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:361
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
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
this module contains the low-level part of the output system
Definition: output_low.F90:117
integer, parameter, public restart_type_dump
Definition: restart.F90:184
integer, parameter, public restart_td
Definition: restart.F90:156
integer, parameter, public restart_type_load
Definition: restart.F90:184
This module handles reading and writing restart information for the states_elec_t.
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.
Interface module to Wannier 90 library.
subroutine, public wannier90lib_initialize_matrix_data(w90main, u_matrix, u_dis_matrix, m_matrix, centers)
Associate w90main object with matrix data.
subroutine, public wannier90lib_wannierization(w90main, gr, space, st, latt, kpoints, options, band_index, warm_start)
Full wannierization.
subroutine, public wannier90lib_init_w90main(namespace, ions, latt, kpoints, st, inp_options, w90main, stdout, stderr, ierr)
Initialize wannier90 library data.
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_write_u_matrices(dir, prefix, kpoints, u_matrix, u_dis_matrix)
Write U and U_dis matrices to file.
subroutine, public wannier_calc_read_u_matrices(wan_opts, kpoints, u_matrix, u_dis_matrix)
Read wannier transformation matrix.
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.
Wannier module.
Definition: wannier.F90:120
subroutine wannier_finalize(wan)
Clean up wannier object data.
Definition: wannier.F90:543
subroutine wannier_init_data_from_file(this, kpoints)
Initialize wannier object data for TD run.
Definition: wannier.F90:323
subroutine wannier_restart_write_data(this, namespace, mc, gr)
Write TD Wannier restart data.
Definition: wannier.F90:348
subroutine wannier_build_effective_lattice(ions, space, gr, latt)
Build the effective lattice used for TD Wannier geometry.
Definition: wannier.F90:270
subroutine wannier_restart_read_data(this, namespace, mc, gr)
Read TD Wannier restart data.
Definition: wannier.F90:397
subroutine wannier_init_from_input(this, namespace, kpoints, ions, space, st, gr)
Initialize wannier object options from input files.
Definition: wannier.F90:188
subroutine wannier_init_parallelization(this, namespace, st, ions, kpoints)
Initialize parallelization for wannier object.
Definition: wannier.F90:297
subroutine wannier_update_matrices(this, iter, namespace, gr, space, st, kpoints, hm, dt)
Update wannier transformation matrix.
Definition: wannier.F90:484
subroutine wannier_write_iter(this, namespace, outp, ions, kpoints)
Write TD Wannier data.
Definition: wannier.F90:448
Wannier options module.
integer, parameter, public td_wannier_method_wannier90
integer, parameter, public td_wannier_method_phase
integer, parameter, public td_wannier_method_none
Describes mesh distribution to nodes.
Definition: mesh.F90:188
Stores all communicators and groups.
Definition: multicomm.F90:208
output handler class
Definition: output_low.F90:166
The states_elec_t class contains all electronic wave functions.
Main object containing all Wannier-related data and methods.
Definition: wannier.F90:155
int true(void)