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 :: phase(:,:)
78 complex(real64), allocatable :: ham_r(:, : ,:)
79 integer, allocatable :: irvec(:, :)
80 integer, allocatable :: ndegen(:)
81 integer :: last_iter = 0
82#ifdef HAVE_WANNIER90
83 type(lib_common_type) :: w90main
84#endif
85
86 contains
87 procedure :: init_from_input => wannier_init_from_input
88 procedure :: init_parallelization => wannier_init_parallelization
89 procedure :: init_data_from_file => wannier_init_data_from_file
90 procedure :: restart_write_data => wannier_restart_write_data
91 procedure :: restart_read_data => wannier_restart_read_data
92 procedure :: write_iter => wannier_write_iter
93 procedure :: update_matrices => wannier_update_matrices
94 final :: wannier_finalize
95 end type wannier_t
96
97contains
98
102 subroutine wannier_init_from_input(this, namespace, kpoints, ions, space, st, gr)
103 class(wannier_t), intent(inout) :: this
104 type(namespace_t), intent(in) :: namespace
105 type(kpoints_t), intent(in) :: kpoints
106 type(ions_t), intent(in) :: ions
107 class(space_t), intent(in) :: space
108 type(states_elec_t), intent(in) :: st
109 class(mesh_t), intent(in) :: gr
110
111 integer :: nrpts
112
114
115 ! Parse all Wannier related options
116 call this%options%parse_oct(namespace)
117 if (this%options%td_method == td_wannier_method_none) then
118 ! No TD wannier functionality requested
120 return
121 end if
122
123 call this%options%parse_win()
124 ! Currently TD Wannier is not supported for the disentanglement case
125 if (this%options%num_bands /= this%options%num_wann) then
126 call messages_not_implemented('TD Wannier: num_bands not equal num_wann')
127 end if
128 ! also not for spin polarized or spinors
129 if (st%d%ispin /= unpolarized) then
130 call messages_not_implemented('TD Wannier: spin polarized and spinors')
131 end if
132 ! and only for 3D systems
133 if (space%dim /= 3) then ! see issue #1466
134 call messages_not_implemented("TD wannier: dimensionality other than 3D")
135 end if
136 ! wannierization is not supported for k-point symmetries
137 if (kpoints%use_symmetries .eqv. .true.) then
138 call messages_not_implemented("TD wannier: k-point symmetries")
139 end if
140 ! nst /= num_bands can occur without excluded bands
141 if (this%options%num_bands /= st%nst) then
142 call messages_not_implemented("TD wannier: Setting nst /= num_bands to exclude bands")
143 end if
144
145 ! Build the effective lattice used for all TD Wannier geometry, and return in this%latt
146 call wannier_build_effective_lattice(ions, space, gr, this%latt)
147
148 safe_allocate(this%u_matrix(1:this%options%num_wann, 1:this%options%num_wann, 1:kpoints%full%npoints))
149 safe_allocate(this%u_dis_matrix(1:this%options%num_bands, 1:this%options%num_wann, 1:kpoints%full%npoints))
150 safe_allocate(this%centers(1:3, 1:this%options%num_wann))
151 safe_allocate(this%spreads(1:this%options%num_wann))
152 safe_allocate(this%phase(1:this%options%num_bands, 1:kpoints%full%npoints))
153 this%u_matrix = m_zero
154 this%u_dis_matrix = m_zero
155 this%centers = m_zero
156 this%spreads = m_zero
157 this%phase = m_z1
159 !Initialize translation vectors needed for calculation of H(R) in Wannier basis
160 nrpts = 1
161 call wannier_calc_wigner_seitz_count(this%latt%rlattice, kpoints%nik_axis(1:3), &
162 this%options%ws_search_size, this%options%ws_distance_tol, nrpts)
163 safe_allocate(this%irvec(1:3, 1:nrpts))
164 safe_allocate(this%ndegen(1:nrpts))
165 call wannier_calc_wigner_seitz_fill(this%latt%rlattice, kpoints%nik_axis(1:3), &
166 this%options%ws_search_size, this%options%ws_distance_tol, nrpts, this%irvec, this%ndegen)
167 safe_allocate(this%ham_r(1:this%options%num_wann, 1:this%options%num_wann, 1:nrpts))
168 this%ham_r = m_zero
169
170
172 end subroutine wannier_init_from_input
180 subroutine wannier_build_effective_lattice(ions, space, gr, latt)
181 type(ions_t), intent(in) :: ions
182 class(space_t), intent(in) :: space
183 class(mesh_t), intent(in) :: gr
184 type(lattice_vectors_t), intent(out) :: latt
185
186 real(real64) :: factor(space%dim)
187 integer :: idir
190
191 call latt%copy(ions%latt)
192
193 factor = m_one
194 do idir = space%periodic_dim + 1, space%dim
195 factor(idir) = m_two * gr%box%bounding_box_l(idir)
196 end do
197 call latt%scale(factor)
198
201
207 subroutine wannier_init_parallelization(this, namespace, st, ions, kpoints)
208 class(wannier_t), intent(inout) :: this
209 type(namespace_t), intent(in) :: namespace
210 type(states_elec_t), intent(in) :: st
211 type(ions_t), intent(in) :: ions
212 type(kpoints_t), intent(in) :: kpoints
213
214#ifdef HAVE_WANNIER90
215 integer :: ierr, nn, iband, ist, nk_local
216#endif
217
219
220 if (this%options%td_method == td_wannier_method_none) then
222 return
223 end if
224
225#ifdef HAVE_WANNIER90
226 !Initialize wannier90 library object, including kpoint parallelization
227 call wannier90lib_init_w90main(namespace, ions, this%latt, kpoints, st, &
228 this%options, this%w90main, stdout, stderr, ierr)
229 if (ierr /= 0) then
230 write(message(1),'(a,i0)') 'Error initializing wannier90 library object: ', ierr
231 call messages_fatal(1)
232 end if
233
234 ! Suppress all disk IO from wannier90 side. The needed output is controlled within octopus
235 this%w90main%output_file = output_file_type() ! resets all file output to false
236
237 ! allocation of m_matrix is done here, since nn HAS to be known (which comes from wannier90 after initialization)
238 ! m_matrix is distributed in k, matching wannier90''s m_matrix_local
239 call w90_get_nn(this%w90main, nn, stdout, stderr, ierr)
240 nk_local = st%d%kpt%nlocal()
241 if (st%d%ispin == spin_polarized) nk_local = nk_local / 2
242 safe_allocate(this%m_matrix(1:this%options%num_bands, 1:this%options%num_bands, 1:nn, 1:nk_local))
243
244 ! Update exclude_list and band_index based on wannier90 input from .win file (if any)
245 safe_allocate(this%options%exclude_list(1:st%nst))
246 this%options%exclude_list = .false.
247 if (allocated(this%w90main%exclude_bands)) then
248 do iband = 1, size(this%w90main%exclude_bands)
249 ist = this%w90main%exclude_bands(iband)
250 this%options%exclude_list(ist) = .true.
251 end do
252 end if
253 ! Currently TD Wannier is not supported for exclude_band case
254 if (any(this%options%exclude_list)) then
255 call messages_not_implemented('TD Wannier: exclude_bands')
256 end if
257 this%options%band_index = pack([(ist, ist=1,st%nst)], this%options%exclude_list .eqv. .false.)
258#endif
259
261
262 end subroutine wannier_init_parallelization
263
268 subroutine wannier_init_data_from_file(this, kpoints)
269 class(wannier_t), intent(inout) :: this
270 type(kpoints_t), intent(in) :: kpoints
271
273
274 if (this%options%td_method == td_wannier_method_none) then
276 return
277 end if
278
279 call wannier_calc_read_centers(this%options, this%centers)
280 call wannier_calc_read_u_matrices(this%options, kpoints, this%u_matrix, this%u_dis_matrix)
281#ifdef HAVE_WANNIER90
282 call wannier90lib_initialize_matrix_data(this%w90main, this%u_matrix, &
283 this%u_dis_matrix, this%m_matrix, this%centers)
284#endif
285
287 end subroutine wannier_init_data_from_file
288
293 subroutine wannier_restart_write_data(this, namespace, mc, gr)
294 class(wannier_t), intent(inout) :: this
295 type(namespace_t), intent(in) :: namespace
296 type(multicomm_t), intent(in) :: mc
297 class(mesh_t), intent(in) :: gr
298
299 type(restart_t) :: restart
300 integer :: ierr
301
303
304 if (this%options%td_method == td_wannier_method_none) then
306 return
307 end if
308
309 call restart%init(namespace, restart_td, restart_type_dump, mc, ierr, mesh=gr)
310 if (ierr /= 0) then
311 message(1) = 'Unable to initialize TD restart for Wannier write.'
312 call messages_fatal(1)
313 end if
314
315 call restart%write_binary('wannier_u_matrix', size(this%u_matrix), this%u_matrix, ierr)
316 if (ierr /= 0) then
317 message(1) = 'Unable to write Wannier restart data (u_matrix).'
318 call messages_fatal(1)
319 end if
320
321 call restart%write_binary('wannier_u_dis_matrix', size(this%u_dis_matrix), this%u_dis_matrix, ierr)
322 if (ierr /= 0) then
323 message(1) = 'Unable to write Wannier restart data (u_dis_matrix).'
324 call messages_fatal(1)
325 end if
326
327 call restart%write_binary('wannier_centers', size(this%centers), this%centers, ierr)
328 if (ierr /= 0) then
329 message(1) = 'Unable to write Wannier restart data (centers).'
330 call messages_fatal(1)
331 end if
332
333 ! Restart dumps do not generally coincide with a wannierization, so the accumulated
334 ! phase is needed to keep it consistent with the U matrix written above
335 call restart%write_binary('wannier_phase', size(this%phase), this%phase, ierr)
336 if (ierr /= 0) then
337 message(1) = 'Unable to write Wannier restart data (phase).'
338 call messages_fatal(1)
339 end if
340
341 call restart%end()
342
345
350 subroutine wannier_restart_read_data(this, namespace, mc, gr)
351 class(wannier_t), intent(inout) :: this
352 type(namespace_t), intent(in) :: namespace
353 type(multicomm_t), intent(in) :: mc
354 class(mesh_t), intent(in) :: gr
355
356 type(restart_t) :: restart
357 integer :: ierr
358
360
361 if (this%options%td_method == td_wannier_method_none) then
363 return
364 end if
365
366 call restart%init(namespace, restart_td, restart_type_load, mc, ierr, mesh=gr)
367 if (ierr /= 0) then
368 message(1) = 'Unable to initialize TD restart for Wannier read.'
369 call messages_fatal(1)
370 end if
371
372 call restart%read_binary('wannier_u_matrix', size(this%u_matrix), this%u_matrix, ierr)
373 if (ierr /= 0) then
374 message(1) = 'Unable to read Wannier restart data (u_matrix).'
375 call messages_fatal(1)
376 end if
377
378 call restart%read_binary('wannier_u_dis_matrix', size(this%u_dis_matrix), this%u_dis_matrix, ierr)
379 if (ierr /= 0) then
380 message(1) = 'Unable to read Wannier restart data (u_dis_matrix).'
381 call messages_fatal(1)
382 end if
383
384 call restart%read_binary('wannier_centers', size(this%centers), this%centers, ierr)
385 if (ierr /= 0) then
386 message(1) = 'Unable to read Wannier restart data (centers).'
387 call messages_fatal(1)
388 end if
389
390 call restart%read_binary('wannier_phase', size(this%phase), this%phase, ierr)
391 if (ierr /= 0) then
392 message(1) = 'Unable to read Wannier restart data (phase).'
393 call messages_fatal(1)
394 end if
395
396#ifdef HAVE_WANNIER90
397 call wannier90lib_initialize_matrix_data(this%w90main, this%u_matrix, &
398 this%u_dis_matrix, this%m_matrix, this%centers)
399#endif
400
401 call restart%end()
402
404 end subroutine wannier_restart_read_data
405
407 subroutine wannier_write_iter(this, namespace, outp, ions, kpoints)
408 class(wannier_t), intent(in) :: this
409 type(namespace_t), intent(in) :: namespace
410 type(output_t), intent(inout) :: outp
411 class(ions_t), intent(in) :: ions
412 type(kpoints_t), intent(in) :: kpoints
413
414 character(len=MAX_PATH_LEN) :: dir, raw_dir
415
416 push_sub(wannier_write_iter)
417
418 ! Only write wannier90 output every n iterations, as specified in input
419 ! This must always coincide with the update, since there is only one variable for both update and output interval.
420 if (mod(this%last_iter, this%options%td_update_interval) == 0) then
421 write(dir, '(a,a,i7.7)') trim(outp%iter_dir),"td.", this%last_iter
422 raw_dir = io_workpath(trim(dir), namespace)
423
424 call io_mkdir(trim(dir), namespace, parents=.true.)
425
426 select case (this%options%td_method)
428 call wannier_calc_write_u_matrices(trim(raw_dir), trim(this%options%prefix), kpoints, this%u_matrix, this%u_dis_matrix)
429 call wannier_calc_write_centers(trim(raw_dir), trim(this%options%prefix), this%centers, ions)
430 call wannier_calc_write_spreads(trim(raw_dir), trim(this%options%prefix), this%spreads)
431 if (this%options%td_write_hr) then
432 call wannier_calc_write_hr_file(trim(raw_dir), trim(this%options%prefix), this%irvec, this%ndegen, this%ham_r)
433 end if
434 case default
435 ! Do nothing
436 end select
437 end if
438
439 pop_sub(wannier_write_iter)
440 end subroutine wannier_write_iter
441
443 subroutine wannier_update_matrices(this, iter, namespace, gr, space, st, kpoints, hm, dt)
444 class(wannier_t), intent(inout) :: this
445 integer, intent(in) :: iter
446 type(namespace_t), intent(in) :: namespace
447 class(mesh_t), intent(in) :: gr
448 class(space_t), intent(in) :: space
449 type(states_elec_t), intent(inout) :: st ! inout because calculation of H(R) requires it
450 type(kpoints_t), intent(in) :: kpoints
451 type(hamiltonian_elec_t), intent(in) :: hm
452 real(real64), intent(in) :: dt
453
454#ifdef HAVE_WANNIER90
455 integer :: iw, ik
456 complex(real64), allocatable :: u_start(:,:,:)
457#endif
460
461 if (this%options%td_method == td_wannier_method_none) then
463 return
464 end if
465
466 ! Keep track of iteration for which the update was performed
467 this%last_iter = iter
468
469 ! This is needed at every step, so that the accumulated phase covers the whole
470 ! interval between two wannierizations
471 call wannier_calc_update_phase(this%options%band_index, st, dt, this%phase)
472
473 if (mod(iter, this%options%td_update_interval) /= 0) then
475 return
476 end if
477
478 select case (this%options%td_method)
480 ! Brute-force wannierization of TD KS states by calling libwannier90
481#ifdef HAVE_WANNIER90
482 ! Warm start from V^dagger U, i.e. the previous U with the phase a stationary state
483 ! would have picked up since then
484 safe_allocate(u_start(1:this%options%num_wann, 1:this%options%num_wann, 1:kpoints%full%npoints))
485 do ik = 1, kpoints%full%npoints
486 do iw = 1, this%options%num_wann
487 u_start(:, iw, ik) = this%phase(:, ik) * this%u_matrix(:, iw, ik)
488 end do
489 end do
490
491 call wannier90lib_wannierization(this%w90main, gr, space, st, this%latt, kpoints, &
492 this%options, this%options%band_index, &
493 this%m_matrix, this%u_dis_matrix, u_start)
495 safe_deallocate_a(u_start)
496
497 ! The new U refers to the states at the current time, so the phase starts over
498 this%phase = m_z1
499
500 ! Convert units and fold the centers into the unit cell
501 do iw = 1, size(this%centers, 2)
502 this%centers(1:3, iw) = units_to_atomic(unit_angstrom, this%w90main%wannier_data%centres(1:3, iw))
503 this%centers(1:3, iw) = this%latt%fold_into_cell(this%centers(1:3, iw)) !using minimum-image convention
504 end do
505
506 !Update the spreads
507 this%spreads = this%w90main%wannier_data%spreads * units_to_atomic(unit_angstrom, 1.0_real64)**2
508
509 !Update lattice model
510 if (this%options%td_write_hr) then
511 call wannier_calc_compute_ham_r(namespace, gr, st, hm, kpoints, this%options, &
512 this%u_matrix, this%irvec, this%ham_r)
513 end if
514#endif
515 case default
516 ! Do nothing
517 end select
518
520 end subroutine wannier_update_matrices
521
523 subroutine wannier_finalize(wan)
524 type(wannier_t), intent(inout) :: wan
525
526 push_sub(wannier_finalize)
527
528 if (wan%options%td_method == td_wannier_method_none) then
529 pop_sub(wannier_finalize)
530 return
531 end if
532
533 safe_deallocate_a(wan%m_matrix)
534 safe_deallocate_a(wan%u_matrix)
535 safe_deallocate_a(wan%u_dis_matrix)
536 safe_deallocate_a(wan%centers)
537 safe_deallocate_a(wan%spreads)
538 safe_deallocate_a(wan%phase)
539 safe_deallocate_a(wan%ham_r)
540 safe_deallocate_a(wan%irvec)
541 safe_deallocate_a(wan%ndegen)
542
543#ifdef HAVE_WANNIER90
544 ! Currently parsing exclude_bands from .win is only supported
545 ! when using libwannier90
546 safe_deallocate_a(wan%options%exclude_list)
547 safe_deallocate_a(wan%options%band_index)
548#endif
549
550 ! Attributes of `lib_common_type` are just pointers to memory we own, so no additional finalisation required
551
552 pop_sub(wannier_finalize)
553 end subroutine wannier_finalize
554
555end module wannier_oct_m
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_z1
Definition: global.F90:211
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_wannierization(w90main, gr, space, st, latt, kpoints, options, band_index, m_matrix, u_matrix_opt, last_u_matrix, warm_start)
Full wannierization.
subroutine, public wannier90lib_initialize_matrix_data(w90main, u_matrix, u_dis_matrix, m_matrix, centers)
Associate w90main object with matrix data.
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_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_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:542
subroutine wannier_init_data_from_file(this, kpoints)
Initialize wannier object data for TD run.
Definition: wannier.F90:320
subroutine wannier_restart_write_data(this, namespace, mc, gr)
Write TD Wannier restart data.
Definition: wannier.F90:345
subroutine wannier_build_effective_lattice(ions, space, gr, latt)
Build the effective lattice used for TD Wannier geometry.
Definition: wannier.F90:267
subroutine wannier_restart_read_data(this, namespace, mc, gr)
Read TD Wannier restart data.
Definition: wannier.F90:402
subroutine wannier_init_from_input(this, namespace, kpoints, ions, space, st, gr)
Initialize wannier object options from input files.
Definition: wannier.F90:189
subroutine wannier_init_parallelization(this, namespace, st, ions, kpoints)
Initialize parallelization for wannier object.
Definition: wannier.F90:294
subroutine wannier_update_matrices(this, iter, namespace, gr, space, st, kpoints, hm, dt)
Update wannier transformation matrix.
Definition: wannier.F90:495
subroutine wannier_write_iter(this, namespace, outp, ions, kpoints)
Write TD Wannier data.
Definition: wannier.F90:459
Wannier options module.
integer, parameter, public td_wannier_method_wannier90
integer, parameter, public td_wannier_method_none
Describes mesh distribution to nodes.
Definition: mesh.F90:187
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)