Octopus
dm_propagation.F90
Go to the documentation of this file.
1!! Copyright (C) 2024 - 2025 S. Pal, Z. Nie, U. De Giovannini
2!! This program is free software; you can redistribute it and/or modify
3!! it under the terms of the GNU General Public License as published by
4!! the Free Software Foundation; either version 2, or (at your option)
5!! any later version.
6!!
7!! This program is distributed in the hope that it will be useful,
8!! but WITHOUT ANY WARRANTY; without even the implied warranty of
9!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10!! GNU General Public License for more details.
11!!
12!! You should have received a copy of the GNU General Public License
13!! along with this program; if not, write to the Free Software
14!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15!! 02110-1301, USA.
16!!
17
18#include "global.h"
19
22 use blas_oct_m
23 use debug_oct_m
28 use global_oct_m
29 use grid_oct_m
32 use ions_oct_m
33 use, intrinsic :: iso_fortran_env
42 use mpi_oct_m
45 use parser_oct_m
48 use space_oct_m
53 use unit_oct_m
55 use v_ks_oct_m
58
59 implicit none
60
61 private
62 public :: &
63 dmp_t, &
67
68 type dmp_t
69 integer :: calculation_mode
70 integer :: basis
71 logical :: unitary_transform
72 type(states_elec_t) :: adiabatic_st
73 integer :: strategy
74 logical :: othn
75 type(restart_t) :: restart_dump
76 integer :: istart, iend
77 complex(real64), allocatable :: rho_offd(:, :)
78 ! 2-Times Model
79 real(real64) :: tmodel(2)
80 real(real64), allocatable :: occ_gs(:, :)
81 ! Uniform Decay
82 real(real64) :: uniform(2)
83 ! EPW Data Parsing and Shared Memory Configuration
84 character(len=256) :: epw_file
85 integer :: iunit
86 integer :: estart, eend, wnst
87 integer :: ia
88 integer :: na(3)
89 real(real64) :: astep(3)
90 integer(int64) :: num
91 integer, allocatable :: kmap(:)
92 type(mpi_grp_t) :: intranode_grp, internode_grp
93#ifdef HAVE_MPI
94 type(MPI_Win) :: window_trans_rate
95#endif
96 contains
97 procedure :: init => dmp_init
98 procedure :: update_trans_rate => dm_propagation_update_trans_rate
99 procedure :: write_dm_proj_basis => td_write_dm_proj_basis
100 end type dmp_t
101
102 ! Defined separately because the VOLATILE attribute is not allowed for derived-type components.
103 real(real32), pointer, volatile :: ave_trans(:)
104
105contains
106
108 subroutine dmp_init(this, namespace, st, space, hm)
109 class(dmp_t), intent(inout) :: this
110 type(namespace_t), intent(in) :: namespace
111 type(states_elec_t), intent(in) :: st
112 class(space_t), intent(in) :: space
113 type(hamiltonian_elec_t), intent(in) :: hm
114
115 type(block_t) :: blk
116 integer :: ncols, nempty
117 real(real64) :: nempty_percent
118
119 push_sub(dmp_init)
120
121 !%Variable TDDMPropagationBasis
122 !%Type integer
123 !%Default Adiabatic
124 !%Section Time-Dependent
125 !%Description
126 !% Decides the basis set for the density matrix propagation.
127 !%Option Adiabatic 01
128 !% Instantaneous eigenstates of the Hamiltonian.
129 !%Option Groundstate 02
130 !% Eigenstates of the Hamiltonian at t=0.
131 !%End
132 call parse_variable(namespace, 'TDDMPropagationBasis', option__tddmpropagationbasis__adiabatic, this%basis)
133 if (.not. varinfo_valid_option('TDDMPropagationBasis', this%basis)) then
134 call messages_input_error(namespace, 'TDDMPropagationBasis')
135 endif
136 call messages_print_var_option('TDDMPropagationBasis', this%basis, namespace=namespace)
137
138 !%Variable TDDMOrthogonal
139 !%Type logical
140 !%Default no
141 !%Section Time-Dependent
142 !%Description
143 !% Use a fully orthonormalized basis when constructing and
144 !% damping the density matrix.
145 !%End
146 call parse_variable(namespace, 'TDDMOrthogonal', .true., this%othn)
147 call messages_print_var_value('TDDMOrthogonal', this%othn, namespace=namespace)
148
149 !%Variable TDDMUnitaryTransformFix
150 !%Type logical
151 !%Default yes
152 !%Section Time-Dependent
153 !%Description
154 !% Applies an additional unitary transformation to the damped wavefunctions
155 !% to maximize their overlap with the reference wavefunctions after damping.
156 !%End
157 call parse_variable(namespace, 'TDDMUnitaryTransformFix', .true., this%unitary_transform)
158 call messages_print_var_value('TDDMUnitaryTransformFix', this%unitary_transform, namespace=namespace)
159
160 !%Variable TDDMBandLowest
161 !%Type integer
162 !%Default 1
163 !%Section Time-Dependent
164 !%Description
165 !% The starting DFT band index used for density matrix propagation.
166 !%End
167 call parse_variable(namespace, 'TDDMBandLowest', 1, this%istart)
168 if (this%istart < 1) then
169 message(1) = "Input: TDDMBandLowest must be positive."
170 call messages_fatal(1, namespace=namespace)
171 end if
173 !%Variable TDDMBandHighest
174 !%Type integer
175 !%Default -1
176 !%Section Time-Dependent
177 !%Description
178 !% The ending DFT band index used for density matrix propagation.
179 !% Defaults to the total number of states.
180 !%End
181 call parse_variable(namespace, 'TDDMBandHighest', st%nst, this%iend)
182 if (this%iend < this%istart .or. this%iend > st%nst) then
183 message(1) = "Input: TDDMBandHighest must be within [TDDMBandLowest, total states]."
184 call messages_fatal(1, namespace=namespace)
185 end if
186 write(message(1), '(a, i0, a, i0)') 'Input: Propagating bands ', this%istart, ' - ', this%iend
187 call messages_info(1, namespace=namespace)
188
189 this%strategy = -1
191 !%Variable TDDMPropagation_uniform_decay
192 !%Type block
193 !%Section Time-Dependent
194 !%Description
195 !% The intra-k transition rates between any pair of states are taken to be constant.
196 !% The population dynamics are therefore determined solely by the state occupations
197 !% and the bath temperature, following Fermi’s golden rule.
198 !% The first column of the block specifies the characteristic lifetime, and the
199 !% second column gives the bath temperature (in Kelvin).
200 !% <tt>%TDDMPropagation_uniform_decay
201 !% <br>&nbsp;&nbsp; Time | Temp
202 !% <br>%</tt>
203 !%End
204 if (parse_block(namespace, 'TDDMPropagation_uniform_decay', blk) == 0) then
205 if (this%strategy /= -1) then
206 message(1) = "Multiple dissipation strategies are not allowed."
207 call messages_fatal(1, namespace=namespace)
208 end if
209 this%strategy = 1
210 ncols = parse_block_cols(blk, 0)
211 if (ncols == 2) then
212 call parse_block_float(blk, 0, 0, this%uniform(1), units_inp%time)
213 call parse_block_float(blk, 0, 1, this%uniform(2))
214 call parse_block_end(blk)
215
216 message(1) = "Info: TDDMPropagation uniform decay approximation:"
217 write(message(2),'(a, f0.2, 1x, 2a, F0.2, 1x, 2a)') ' [lifetime, temperature] = [', &
218 this%uniform(1), trim(units_abbrev(units_out%time)), ', ', this%uniform(2), trim(units_abbrev(unit_kelvin)), ']'
219 call messages_info(2, namespace=namespace)
220 else
221 message(1) = "Input: TDDMPropagation_uniform_decay block must have 2 columns."
222 call messages_fatal(1, namespace=namespace)
223 end if
224 end if
225
226 !%Variable TDDMPropagation_2Times
227 !%Type block
228 !%Section Time-Dependent
229 !%Description
230 !% Two times approximation for the jump operator in the master equation.
231 !% S. A. Sato <i>et al.</i>, <i>Phys. Rev. B</i> 99, 214302 (2019).
232 !%
233 !% <tt>%TDDMPropagation_2Times
234 !% <br>&nbsp;&nbsp; t1 | t2
235 !% <br>%</tt>
236 !%End
237 if (parse_block(namespace, 'TDDMPropagation_2Times', blk) == 0) then
238 if (this%strategy /= -1) then
239 message(1) = "Multiple dissipation strategies are not allowed."
240 call messages_fatal(1, namespace=namespace)
241 end if
242 this%strategy = 2
243 ncols = parse_block_cols(blk, 0)
244 if (ncols == 2) then
245 call parse_block_float(blk, 0, 0, this%tmodel(1), units_inp%time)
246 call parse_block_float(blk, 0, 1, this%tmodel(2), units_inp%time)
247 call parse_block_end(blk)
248
249 message(1) = "Info: TDDMPropagation 2-times approximation:"
250 write(message(2),'(a, f12.6, a, f12.6, a,a)') &
251 ' [t1, t2] = [', this%tmodel(1) , ', ', this%tmodel(2), '] ', &
252 trim(units_abbrev(units_out%time))
253 call messages_info(2, namespace=namespace)
254 else
255 message(1) = "Input: TDDMPropagation_2Times block must have 2 columns."
256 call messages_fatal(1, namespace=namespace)
257 end if
258 ! for two times model, only orthonormalized basis is allowed
259 if (.not. this%othn) then
260 this%othn = .true.
261 message(1) = "Overriding input: TDDMOrthogonal set to yes for TDDMPropagation_2Times."
262 call messages_warning(1, namespace=namespace)
263 end if
264 end if
265
266 !%Variable TDDMPropagation_from_epw
267 !%Type string
268 !%Default "-"
269 !%Section Time-Dependent
270 !%Description
271 !% Specifies the transition-rate file generated by EPW. Once loaded, the
272 !% simulation includes all intra-k and inter-k scattering processes, with
273 !% the electron dynamics governed by Fermi’s Golden Rule. This option
274 !% requires EPWBandLowest to be set.
275 !%End
276 call parse_variable(namespace, 'TDDMPropagation_from_epw', '-', this%epw_file)
277 if (trim(this%epw_file) /= '-') then
278 if (bitand(hm%kpoints%method, kpoints_monkh_pack) == 0) then
279 write(message(1),'(a)') 'Only Monkhorst-Pack k-point meshes are supported in the EPW-DMPropagation strategy.'
280 call messages_fatal(1, namespace = namespace)
281 end if
282 if (hm%kpoints%reduced%nshifts /= 1) then
283 write(message(1),'(a)') 'Multiple Monkhorst-Pack shifts are not supported in the EPW-DMPropagation strategy.'
284 call messages_fatal(1, namespace = namespace)
285 end if
286 if (space%dim /= 3) then
287 write(message(1),'(a)') 'Only 3D systems are supported in the EPW-DMPropagation strategy.'
288 call messages_fatal(1, namespace = namespace)
289 end if
290
291 if (this%strategy /= -1) then
292 message(1) = "Multiple dissipation strategies are not allowed."
293 call messages_fatal(1, namespace=namespace)
294 end if
295 this%strategy = 3
296 write(message(1),'(a, a)') "Info: TDDMPropagation transition rates from file: ", trim(this%epw_file)
297 call messages_info(1, namespace=namespace)
298 end if
299
300 !%Variable EPWBandLowest
301 !%Type integer
302 !%Default -1
303 !%Section Time-Dependent
304 !%Description
305 !% The starting DFT band index used for damping.
306 !%
307 !% Since EPW transition rates are calculated for a subset of DFT bands,
308 !% this variable tells the code which global DFT band corresponds
309 !% to damping band #1.
310 !%
311 !% Example: If you damp DFT bands 10 through 15, set EPWBandLowest = 10.
312 !%End
313 if (this%strategy == 3) then
314 call parse_variable(namespace, 'EPWBandLowest', 0, this%estart)
315 if (this%estart < this%istart .or. this%estart > this%iend) then
316 write(message(1), '(a)') 'Input: EPWBandLowest must be within [TDDMBandLowest, TDDMBandHighest].'
317 call messages_fatal(1, namespace=namespace)
318 end if
319 end if
320
321 ! Sanity checks
322 if (this%calculation_mode == option__tddmpropagation__collision_integral .and. this%strategy /= 3) then
323 message(1) = "Warning: TDDMPropagation_from_epw is required for collision integral."
324 message(2) = " Add TDDMPropagation_from_epw and rerun."
325 call messages_fatal(2, namespace=namespace)
326 end if
327
328 call parse_variable(namespace, 'ExtraStates', 0, nempty)
329 call parse_variable(namespace, 'ExtraStatesInPercent', m_zero, nempty_percent)
330 if (nempty == 0 .and. nempty_percent < m_epsilon) then
331 message(1) = "Warning: TDDMPropagation requires a number of empty states."
332 message(2) = " Add ExtraStates and rerun."
333 call messages_fatal(2, namespace=namespace)
334 end if
335
336 if (st%parallel_in_states) then
337 message(1) = "Warning: TDDMPropagation does not support parallel states."
338 message(2) = " Remove ParallelStates and rerun."
339 call messages_fatal(2, namespace=namespace)
340 end if
341
342 if (st%d%ispin == spin_polarized .and. this%strategy == 3) then
343 call messages_not_implemented('Spin-polarized TDDMPropagation with EPW', namespace=namespace)
344 end if
345
346 pop_sub(dmp_init)
347
348 end subroutine dmp_init
349
351 subroutine dm_propagation_init_run(dmp, namespace, space, gr, ions, st, hm, mc, from_scratch)
352 type(dmp_t), intent(inout) :: dmp
353 type(namespace_t), intent(in) :: namespace
354 type(electron_space_t), intent(in) :: space
355 type(grid_t), intent(in) :: gr
356 type(ions_t), intent(in) :: ions
357 type(states_elec_t), intent(in) :: st
358 type(hamiltonian_elec_t), intent(in) :: hm
359 type(multicomm_t), intent(in) :: mc
360 logical, intent(in) :: from_scratch
361
362 integer :: ierr, act_nst
363 type(restart_t) :: restart_load
364
366
367 ! By default, wavefunctions are copied. In principle, exclude_eigenval should be true.
368 ! But we need its allocation
369 call states_elec_copy(dmp%adiabatic_st, st, special=.true.)
370
371 if (from_scratch .or. dmp%basis == option__tddmpropagationbasis__groundstate) then
372 call restart_load%init(namespace, restart_gs, restart_type_load, mc, ierr, mesh=gr, exact=.true.)
373 else
374 call restart_load%init(namespace, restart_dm, restart_type_load, mc, ierr, mesh=gr, exact=.true.)
375 end if
376
377 if (ierr == 0) then
378 call states_elec_load(restart_load, namespace, space, dmp%adiabatic_st, gr, hm%kpoints, fixed_occ=st%restart_fixed_occ, &
379 ierr=ierr, label = ": DM-basis")
380 else
381 message(1) = 'Unable to read DM-basis wavefunctions.'
382 call messages_fatal(1, namespace=namespace)
383 end if
384
385 call restart_load%end()
386
387 ! TDDMPropagation_2Times
388 if (dmp%strategy == 2) then
389 safe_allocate(dmp%occ_gs(1:st%nst, 1:st%nik))
390 dmp%occ_gs = dmp%adiabatic_st%occ
391 end if
392
393 ! dmp%ave_trans: replicated on each node, shared within the node
394 if (dmp%strategy == 3) call iopar_open_trans_rate(namespace, ions, hm, st%system_grp, dmp)
395
396 ! record only adiabatic states
397 if (dmp%basis == option__tddmpropagationbasis__adiabatic) then
398 call dmp%restart_dump%init(namespace, restart_dm, restart_type_dump, mc, ierr, mesh=gr)
399 end if
400
401 ! record off-diagonals
402 act_nst = dmp%iend - dmp%istart + 1
403 safe_allocate(dmp%rho_offd(1:act_nst*(act_nst-1)/2, st%d%kpt%start:st%d%kpt%end))
404
406 end subroutine dm_propagation_init_run
407
408 subroutine dm_end_run(system_grp, dmp)
409 type(mpi_grp_t), intent(in) :: system_grp
410 type(dmp_t), intent(inout) :: dmp
411
412 push_sub(dm_end_run)
413
414 if (dmp%basis == option__tddmpropagationbasis__adiabatic) then
415 call dmp%restart_dump%end()
416 end if
417
418 call states_elec_end(dmp%adiabatic_st)
419
420 if (dmp%strategy == 3) call iopar_close_trans_rate(system_grp, dmp)
421
422 safe_deallocate_a(dmp%occ_gs)
423 safe_deallocate_a(dmp%rho_offd)
424
425 pop_sub(dm_end_run)
426 end subroutine dm_end_run
427
429 subroutine dm_propagation_run(dmp, namespace, space, gr, ions, st, mc, hm, ks, iter, dt, ext_partners, update_energy)
430 type(dmp_t), intent(inout) :: dmp
431 type(namespace_t), intent(in) :: namespace
432 type(electron_space_t), intent(in) :: space
433 type(grid_t), intent(in) :: gr
434 type(ions_t), intent(in) :: ions
435 type(states_elec_t), intent(inout) :: st
436 type(multicomm_t), intent(in) :: mc
437 type(hamiltonian_elec_t), intent(inout) :: hm
438 type(v_ks_t), intent(inout) :: ks
439 integer, intent(in) :: iter
440 real(real64), intent(in) :: dt
441 type(partner_list_t), intent(in) :: ext_partners
442 logical, optional, intent(in) :: update_energy
443
444 real(real64), parameter :: zero = 1.0e-15_real64
445 type(eigensolver_t) :: eigens
446 real(real64) :: nrm2_tdks(st%nst, st%nik), population(3), leak
447 integer :: ik, act_nst
448 logical :: update_energy_
449 type(states_elec_t) :: resd_st
450 complex(real64), allocatable :: overlap_ad_ks(:, :, :), overlap_resd_ks(:, :, :), rho_mat_k(:, :, :)
451 integer, allocatable :: nresd_k(:)
452
453 push_sub_with_profile(dm_propagation_run)
454
455 ! hm is updated after each td propagation.
456 if (dmp%basis == option__tddmpropagationbasis__adiabatic) then
457 call eigensolver_init(eigens, namespace, gr, dmp%adiabatic_st, hm, mc, space)
458 eigens%converged = 0
459 call eigens%run(namespace, gr, dmp%adiabatic_st, hm, space, ext_partners, iter)
460 end if
461
462 act_nst = dmp%iend - dmp%istart + 1
463
464 safe_allocate(overlap_ad_ks(1:st%nst, 1:st%nst, st%d%kpt%start:st%d%kpt%end))
465 safe_allocate(overlap_resd_ks(1:st%nst, 1:st%nst, st%d%kpt%start:st%d%kpt%end))
466 safe_allocate(rho_mat_k(2*act_nst, 2*act_nst, st%d%kpt%start:st%d%kpt%end))
467 safe_allocate(nresd_k(st%d%kpt%start:st%d%kpt%end))
468
469 population = 0.0_real64
470
471 ! Create a copy of the TDKS states to initialise the residuals
472 call states_elec_copy(resd_st, st, exclude_eigenval = .true.)
473
474 ! Store all density matrices for potential future communication
475 do ik = st%d%kpt%start, st%d%kpt%end
476 ! pop = \sum_{i,k} f_{i,k} <\psi_{i,k} | \psi_{i,k}>
477 call total_population(ik, st, gr, nrm2_tdks(:, ik), population(1))
478 ! S^{\phi,\psi}_{ij} = <\phi_i | \psi_j>
479 call calc_overlap_state(ik, gr, dmp%adiabatic_st, st, dmp%istart, dmp%iend, dmp%istart, dmp%iend, overlap_ad_ks(:, :, ik))
480 ! population before damping, set occupation as well
481 call population_in_adiabatic(ik, dmp%adiabatic_st, st, overlap_ad_ks(:, :, ik), dmp%istart, dmp%iend, population(2))
482
483 ! residual |d_j> = |\psi_j> - \sum_i S^{\phi,\psi}_{ij} |\phi_i>
484 ! S^{d,\psi}_{ij} = <d_i | \psi_j>
485 call construct_residuals(gr, namespace, dmp%adiabatic_st, st, ik, dmp%othn, dmp%istart, dmp%iend, &
486 overlap_ad_ks(:, :, ik), nrm2_tdks(:, ik), nresd_k(ik), overlap_resd_ks(:, :, ik), resd_st)
487
488 ! Active block: istart:iend, nst+istart:nst+istart+nresd-1, allocated shape: (2*nst, 2*nst, :)
489 call construct_density_matrix(nresd_k(ik), ik, st, dmp%istart, dmp%iend, overlap_ad_ks(:, :, ik), &
490 overlap_resd_ks(:, :, ik), rho_mat_k(:, :, ik), dmp%rho_offd(:, ik))
491 end do
492
493 ! broadcast the instanteous occupation for Pauli blocking
494 call broadcast_occupation(dmp%adiabatic_st%occ, dmp%adiabatic_st%d%kpt, st%parallel_in_states, dmp%istart, dmp%iend)
495
496 ! dissipate the density matrix
497 call dissipation(hm, st, namespace, nresd_k, dt, dmp, rho_mat_k)
498
499 do ik = st%d%kpt%start, st%d%kpt%end
500 ! reconstruct wavefunctions. Active block: (nresd+nst, nresd+nst, :), allocated shape: (2*nst, 2*nst, :)
501 call update_st(dmp, ik, gr, namespace, nresd_k(ik), overlap_ad_ks(:, :, ik), overlap_resd_ks(:, :, ik), nrm2_tdks(:, ik), &
502 resd_st, st, rho_mat_k(:, :, ik), population(3))
503 end do
504
505 call states_elec_end(resd_st)
506
507 safe_deallocate_a(overlap_ad_ks)
508 safe_deallocate_a(overlap_resd_ks)
509
510 call broadcast_occupation(st%occ, st%d%kpt, st%parallel_in_states, dmp%istart, dmp%iend)
511
512 safe_deallocate_a(rho_mat_k)
513 safe_deallocate_a(nresd_k)
514
515 call st%d%kpt%mpi_grp%allreduce_inplace(population, 3, mpi_double_precision, mpi_sum)
516
517 write(message(1), '(a,E21.14,a,E21.14,a,E21.14,a)') 'DMPopulation: ', population(1), &
518 ' (', population(2), ' in basis ) before damping; ', population(3), ' after damping'
519 call messages_info(1)
520
521 leak = population(1) - population(3)
522 if (abs(leak) > zero) then
523 write(message(1), '(a,E15.8,a,I8)') 'Leakage: ', leak, '(after damping) at time step', iter
524 call messages_info(1)
525 end if
526 dmp%adiabatic_st%qtot = population(1)
527
528 ! renew hamiltonian
529 call density_calc(st, gr, st%rho)
530 update_energy_ = optional_default(update_energy, .true.)
531 call v_ks_calc(ks, namespace, space, hm, st, ions, ext_partners, calc_eigenval = update_energy_, &
532 time = abs(iter * dt), calc_energy = update_energy_)
533
534 if (dmp%basis == option__tddmpropagationbasis__adiabatic) then
535 call eigensolver_end(eigens)
536 end if
537
538 pop_sub_with_profile(dm_propagation_run)
539
540 end subroutine dm_propagation_run
541
544 subroutine total_population(ik, st, gr, nrm2, pop)
545 integer, intent(in) :: ik
546 type(states_elec_t), intent(in) :: st
547 type(grid_t), intent(in) :: gr
548 real(real64), contiguous, intent(out) :: nrm2(:)
549 real(real64), intent(inout) :: pop
550
551 integer :: ib, i_minst, i_maxst
552
553 push_sub(total_population)
554
555 assert(pop >= 0.0_real64)
556 assert(size(nrm2) == st%nst)
557
558 do ib = st%group%block_start, st%group%block_end
559 i_minst = states_elec_block_min(st, ib)
560 i_maxst = states_elec_block_max(st, ib)
561 call mesh_batch_nrm2(gr, st%group%psib(ib, ik), nrm2(i_minst:i_maxst), reduce = .false.)
562 end do
563 nrm2(1:st%nst) = nrm2(1:st%nst)**2
564 if (gr%parallel_in_domains) then
565 call gr%allreduce(nrm2, dim = st%nst)
566 end if
567
568 pop = pop + sum(st%occ(1:st%nst, ik) * nrm2(1:st%nst)) * st%kweights(ik)
569
570 pop_sub(total_population)
571
572 end subroutine total_population
573
577 subroutine calc_overlap_single(ik, gr, st, psi, istart, iend, overlap, reduce)
578 integer, intent(in) :: ik
579 type(grid_t), intent(in) :: gr
580 type(states_elec_t), intent(in) :: st
581 complex(real64), contiguous, intent(in) :: psi(:,:)
582 integer, intent(in) :: istart
583 integer, intent(in) :: iend
584 complex(real64), intent(out) :: overlap(:)
585 logical, optional, intent(in) :: reduce
586
587 integer :: ib, i_minst, i_maxst, ist
588 complex(real64), allocatable :: phi(:, :)
589
590 push_sub_with_profile(calc_overlap_single)
591
592 assert(iend >= istart)
593 assert(ubound(overlap, dim = 1) == st%nst)
594
595 safe_allocate(phi(1:gr%np, st%d%dim))
596
597 overlap = m_z0
598
599 do ib = st%group%block_start, st%group%block_end
600 i_minst = states_elec_block_min(st, ib)
601 i_maxst = states_elec_block_max(st, ib)
602 if (i_minst >= istart .and. i_maxst <= iend) then
603 call zmesh_batch_mf_dotp(gr, st%group%psib(ib, ik), psi, overlap(i_minst:i_maxst), reduce=.false., &
604 nst=i_maxst-i_minst+1)
605 else
606 do ist = max(i_minst, istart), min(i_maxst, iend)
607 call states_elec_get_state(st, gr, ist, ik, phi)
608 overlap(ist) = zmf_dotp(gr, st%d%dim, phi, psi, reduce = .false.)
609 end do
610 end if
611 end do
612
613 safe_deallocate_a(phi)
614
615 if (optional_default(reduce, .false.)) then
616 call gr%allreduce(overlap, dim = st%nst)
617 end if
618
619 pop_sub_with_profile(calc_overlap_single)
620 end subroutine calc_overlap_single
621
624 subroutine calc_overlap_state(ik, gr, ad_st, st, istart_ad, iend_ad, istart_st, iend_st, overlap)
625 integer, intent(in) :: ik
626 type(grid_t), intent(in) :: gr
627 type(states_elec_t), intent(in) :: ad_st
628 type(states_elec_t), intent(in) :: st
629 integer, intent(in) :: istart_ad
630 integer, intent(in) :: iend_ad
631 integer, intent(in) :: istart_st
632 integer, intent(in) :: iend_st
633 complex(real64), intent(out) :: overlap(:, :)
634
635 integer :: ist, jst, ib, jb, i_minst, i_maxst, j_minst, j_maxst
636 complex(real64), allocatable :: psi(:, :), dot(:)
638 push_sub_with_profile(calc_overlap_state)
639
640 assert(istart_ad <= iend_ad)
641 assert(istart_st <= iend_st)
642 assert(ubound(overlap, dim = 1) == ad_st%nst)
643 assert(ubound(overlap, dim = 2) == st%nst)
644
645 safe_allocate(psi(1:gr%np, st%d%dim))
646 safe_allocate(dot(1:st%nst))
647
648 overlap = m_z0
649
650 do jb = st%group%block_start, st%group%block_end
651 j_minst = states_elec_block_min(st, jb)
652 j_maxst = states_elec_block_max(st, jb)
653
654 ! full st batch
655 if (j_minst >= istart_st .and. j_maxst <= iend_st) then
656 do ib = ad_st%group%block_start, ad_st%group%block_end
657 i_minst = states_elec_block_min(ad_st, ib)
658 i_maxst = states_elec_block_max(ad_st, ib)
659
660 ! full ad_st batch, full st batch
661 if (i_minst >= istart_ad .and. i_maxst <= iend_ad) then
662 call zmesh_batch_dotp_matrix(gr, ad_st%group%psib(ib, ik), st%group%psib(jb, ik), overlap, reduce=.false.)
663
664 ! partial ad_st batch, full st batch
665 else
666 do ist = max(i_minst, istart_ad), min(i_maxst, iend_ad)
667 call states_elec_get_state(ad_st, gr, ist, ik, psi)
668 call zmesh_batch_mf_dotp(gr, st%group%psib(jb, ik), psi, dot(j_minst:j_maxst), reduce=.false., &
669 nst=j_maxst-j_minst+1)
670 overlap(ist, j_minst:j_maxst) = conjg(dot(j_minst:j_maxst))
671 end do
672 end if
673 end do
674
675 ! partial st batch
676 else
677 do jst = max(j_minst, istart_st), min(j_maxst, iend_st)
678 call states_elec_get_state(st, gr, jst, ik, psi)
679 call calc_overlap_single(ik, gr, ad_st, psi, istart_ad, iend_ad, overlap(:,jst), reduce=.false.)
680 end do
681 end if
682 end do
683
684 if (gr%parallel_in_domains) then
685 call gr%allreduce(overlap)
686 end if
687
688 safe_deallocate_a(psi)
689 safe_deallocate_a(dot)
690
691 pop_sub_with_profile(calc_overlap_state)
692
693 end subroutine calc_overlap_state
694
697 subroutine population_in_adiabatic(ik, ad_st, st, overlap, istart, iend, pop)
698 integer, intent(in) :: ik
699 type(states_elec_t), intent(inout) :: ad_st
700 type(states_elec_t), intent(in) :: st
701 complex(real64), contiguous, intent(in) :: overlap(:, :)
702 integer, intent(in) :: istart
703 integer, intent(in) :: iend
704 real(real64), intent(inout) :: pop
705
706 integer :: ist, jst
707
709
710 assert(ubound(overlap, dim = 1) == ad_st%nst)
711 assert(ubound(overlap, dim = 2) == st%nst)
712
713 ! Assign ad_st occupation and store in dm_proj_basis (also used for hopping rate calculation)
714 ad_st%occ(1:ad_st%nst, ik) = 0.0_real64
715 do jst = istart, iend
716 do ist = istart, iend
717 ad_st%occ(ist, ik) = ad_st%occ(ist, ik) + &
718 (real(overlap(ist, jst))**2 + aimag(overlap(ist, jst))**2) * st%occ(jst, ik)
719 end do
720 end do
721
722 pop = pop + sum(ad_st%occ(istart:iend, ik)) * ad_st%kweights(ik)
723
725
726 end subroutine population_in_adiabatic
727
743 subroutine construct_residuals(gr, namespace, ad_st, st, ik, othn, istart, iend, &
744 overlap_ad_ks, nrm2_tdks, nresd, overlap_resd_ks, resd)
745 type(grid_t), intent(in) :: gr
746 type(namespace_t), intent(in) :: namespace
747 type(states_elec_t), intent(in) :: ad_st
748 type(states_elec_t), intent(in) :: st
749 integer, intent(in) :: ik
750 logical, intent(in) :: othn
751 integer, intent(in) :: istart
752 integer, intent(in) :: iend
753 complex(real64), contiguous, intent(in) :: overlap_ad_ks(:, :)
754 real(real64), contiguous, intent(in) :: nrm2_tdks(:)
755 integer, intent(out) :: nresd
756 complex(real64), contiguous, intent(out) :: overlap_resd_ks(:, :)
757 type(states_elec_t), intent(inout) :: resd
758
759 integer :: ib, i, j, i_minst, i_maxst
760 complex(real64), allocatable :: d_j(:, :), phi(:, :)
761 real(real64), parameter :: small_rho = 1.0e-14_real64
762 real(real64), parameter :: small_resd = 1.0e-7_real64
763 real(real64) :: nrm_dj, nrm2_dj
764 logical, allocatable :: mask(:)
765
766 push_sub_with_profile(construct_residuals)
767
768 assert(istart <= iend)
769 assert(ubound(overlap_ad_ks, dim = 1) == ad_st%nst)
770 assert(ubound(overlap_ad_ks, dim = 2) == st%nst)
771 assert(ubound(overlap_resd_ks, dim = 1) == resd%nst)
772 assert(ubound(overlap_resd_ks, dim = 2) == st%nst)
773
774 safe_allocate(d_j(1:gr%np, st%d%dim))
775 safe_allocate(phi(1:gr%np, ad_st%d%dim))
776 safe_allocate(mask(1:st%nst))
777
778 overlap_resd_ks = m_z0
779
780 if (.not. othn) then
781
782 ! Iterate over TDKS batches, construct the residuals
783 do j = istart, iend
784 call states_elec_get_state(st, gr, j, ik, d_j)
785 ! Compute |\psi_j > - sum_i S^{\phi,\psi}_{ij} |\phi_i >
786 do ib = ad_st%group%block_start, ad_st%group%block_end
787 i_minst = states_elec_block_min(ad_st, ib)
788 i_maxst = states_elec_block_max(ad_st, ib)
789 if (i_minst >= istart .and. i_maxst <= iend) then
790 call zbatch_axpy_function(gr%np, -overlap_ad_ks(i_minst:i_maxst, j), &
791 ad_st%group%psib(ib, ik), d_j, nst=i_maxst-i_minst+1)
792 else
793 do i = max(i_minst, istart), min(i_maxst, iend)
794 call states_elec_get_state(ad_st, gr, i, ik, phi)
795 call lalg_axpy(gr%np, ad_st%d%dim, -overlap_ad_ks(i, j), phi, d_j)
796 end do
797 end if
798 end do
799
800 ! reset the residuals
801 call states_elec_set_state(resd, gr, j, ik, d_j)
802
803 ! Overlap S^{d,\psi} = < d | \psi>
804 ! This on-the-fly calculation keeps d_j in cache, avoiding the massive overhead of re-reading the grid later.
805 call calc_overlap_single(ik, gr, st, d_j, istart, iend, overlap_resd_ks(j,:), reduce=.false.)
806 enddo
807
808 nresd = iend - istart + 1
809
810 else
811
812 ! Construct the orthonormalized residuals
813 nresd = 0
814
815 ! Iterate over TDKS states, construct the linearly-independent terms as residuals
816 do j = istart, iend
817 ! nrm2_dj = nrm2_tdks - \sum_i |S^{\phi,\psi}_{ij}|^2
818 nrm2_dj = nrm2_tdks(j) - sum(real(overlap_ad_ks(istart:iend, j))**2) - sum(aimag(overlap_ad_ks(istart:iend, j))**2)
819 if (nrm2_dj > small_rho) then
820 ! scale the TDKS wavefunction to make the residual terms approximately normalized
821 call states_elec_get_state(st, gr, j, ik, d_j)
822 nrm_dj = sqrt(nrm2_dj)
823 call lalg_scal(gr%np, resd%d%dim, m_one / nrm_dj, d_j)
824
825 ! substract the overlap with ad states
826 ! Compute 1/|d_j| |\psi_j > - 1/|d_j| sum_i S^{\phi,\psi}_{ij} |\phi_i >
827 do ib = ad_st%group%block_start, ad_st%group%block_end
828 i_minst = states_elec_block_min(ad_st, ib)
829 i_maxst = states_elec_block_max(ad_st, ib)
830 if (i_minst >= istart .and. i_maxst <= iend) then
831 call zbatch_axpy_function(gr%np, -overlap_ad_ks(i_minst:i_maxst, j) / nrm_dj, &
832 ad_st%group%psib(ib, ik), d_j, nst=i_maxst-i_minst+1)
833 else
834 do i = max(i_minst, istart), min(i_maxst, iend)
835 call states_elec_get_state(ad_st, gr, i, ik, phi)
836 call lalg_axpy(gr%np, ad_st%d%dim, -overlap_ad_ks(i, j) / nrm_dj, phi, d_j)
837 end do
838 end if
839 end do
840
841 mask = .true.
842 mask(istart:iend) = .false.
843 call zstates_elec_orthogonalize_single_batch(ad_st, gr, st%nst, ik, d_j, mask=mask)
844
845 ! substract the overlap with previous residuals
846 if (nresd > 0) then
847 mask = .true.
848 mask(istart:istart+nresd-1) = .false.
849 call zstates_elec_orthogonalize_single_batch(resd, gr, istart+nresd-1, ik, d_j, mask=mask)
850 end if
851 ! screen the small terms
852 nrm_dj = zmf_nrm2(gr, resd%d%dim, d_j, reduce=.true.)
853 if (nrm_dj > small_resd) then
854 call lalg_scal(gr%np, resd%d%dim, m_one / nrm_dj, d_j)
855 nresd = nresd + 1
856 call states_elec_set_state(resd, gr, istart+nresd-1, ik, d_j)
857
858 ! Overlap matrix S^{d,\psi}_{ji} = < d_j | \psi_i >
859 call calc_overlap_single(ik, gr, st, d_j, istart, iend, overlap_resd_ks(istart+nresd-1,:), reduce=.false.)
860 end if
861 end if
862 enddo
863 end if
864
865 if (gr%parallel_in_domains) then
866 call gr%allreduce(overlap_resd_ks)
867 end if
868
869 overlap_resd_ks = conjg(overlap_resd_ks)
870
871 safe_deallocate_a(d_j)
872 safe_deallocate_a(phi)
873 safe_deallocate_a(mask)
874
875 pop_sub_with_profile(construct_residuals)
876
877 end subroutine construct_residuals
878
894 subroutine construct_density_matrix(nresd, ik, st, istart, iend, overlap_ad_ks, overlap_resd_ks, rho_mat, rho_offd)
895 integer, intent(in) :: nresd
896 integer, intent(in) :: ik
897 type(states_elec_t), intent(in) :: st
898 integer, intent(in) :: istart
899 integer, intent(in) :: iend
900 complex(real64), contiguous, intent(in) :: overlap_ad_ks(:, :)
901 complex(real64), contiguous, intent(in) :: overlap_resd_ks(:, :)
902 complex(real64), contiguous, intent(out) :: rho_mat(:, :)
903 complex(real64), contiguous, intent(out) :: rho_offd(:)
904
905 integer :: ist, jst, lst, act_nst, idx
906 real(real64) :: sqrt_f
907 complex(real64), allocatable :: s_ad_scaled(:, :), s_resd_scaled(:, :)
908
910
911 act_nst = iend - istart + 1
912
913 assert(istart <= iend)
914 assert(ubound(overlap_ad_ks, dim = 1) == st%nst)
915 assert(ubound(overlap_ad_ks, dim = 2) == st%nst)
916 assert(ubound(overlap_resd_ks, dim = 1) == st%nst)
917 assert(ubound(overlap_resd_ks, dim = 2) == st%nst)
918 assert(ubound(rho_mat, dim = 1) == 2*act_nst)
919 assert(ubound(rho_mat, dim = 2) == 2*act_nst)
920 assert(ubound(rho_offd, dim = 1) == act_nst*(act_nst-1)/2)
921
922 safe_allocate(s_ad_scaled(st%nst, st%nst))
923 if (nresd > 0) then
924 safe_allocate(s_resd_scaled(st%nst, st%nst))
925 end if
926
927 ! initialize to zero
928 rho_mat = m_z0
929 s_ad_scaled = m_z0
930 if (nresd > 0) then
931 s_resd_scaled = m_z0
932 end if
933
934 ! scale S matrix
935 do lst = istart, iend
936 sqrt_f = sqrt(st%occ(lst, ik))
937 s_ad_scaled(istart:iend, lst) = overlap_ad_ks(istart:iend, lst) * sqrt_f
938 if (nresd > 0) then
939 s_resd_scaled(istart:istart+nresd-1, lst) = overlap_resd_ks(istart:istart+nresd-1, lst) * sqrt_f
940 end if
941 end do
942
943 ! ad-ad
944 call blas_herk('U', 'N', act_nst, act_nst, 1.0_real64, s_ad_scaled(istart,istart), st%nst, 0.0_real64, &
945 rho_mat(1, 1), 2*act_nst)
946 if (nresd > 0) then
947 ! resd-resd
948 call blas_herk('U', 'N', nresd, act_nst, 1.0_real64, s_resd_scaled(istart,istart), st%nst, 0.0_real64, &
949 rho_mat(act_nst+1, act_nst+1), 2*act_nst)
950 ! ad-resd
951 call blas_gemm('N', 'C', act_nst, nresd, act_nst, m_z1, s_ad_scaled(istart, istart), st%nst, &
952 s_resd_scaled(istart,istart), st%nst, m_z0, rho_mat(1, act_nst+1), 2*act_nst)
953 end if
954
955 !$omp parallel do private(jst, ist)
956 do jst = 1, act_nst
957 ! mirror ad-ad lower triangle
958 do ist = 1, jst - 1
959 rho_mat(jst, ist) = conjg(rho_mat(ist, jst))
960 end do
961
962 ! mirror ad-resd to resd-ad (bottom-left block)
963 do ist = 1, nresd
964 rho_mat(act_nst+ist, jst) = conjg(rho_mat(jst, act_nst+ist))
965 end do
966 end do
967 !$omp end parallel do
968
969 !$omp parallel do private(jst, ist)
970 do jst = 1, nresd
971 ! mirror resd-resd lower triangle
972 do ist = 1, jst - 1
973 rho_mat(act_nst+jst, act_nst+ist) = conjg(rho_mat(act_nst+ist, act_nst+jst))
974 end do
975 end do
976 !$omp end parallel do
977
978 safe_deallocate_a(s_ad_scaled)
979 safe_deallocate_a(s_resd_scaled)
980
981 ! off-diagonal elements
982 idx = 0
983 do jst = 1, act_nst
984 do ist = 1, jst - 1
985 idx = idx + 1
986 rho_offd(idx) = rho_mat(ist, jst)
987 end do
988 end do
989
991 end subroutine construct_density_matrix
992
993 subroutine broadcast_occupation(occ, kpt, parstate, istart, iend)
994 real(real64), contiguous, intent(inout) :: occ(:, :)
995 type(distributed_t), intent(in) :: kpt
996 logical, intent(in) :: parstate
997 integer, intent(in) :: istart
998 integer, intent(in) :: iend
999
1000 integer :: incount, act_nst
1001 integer, allocatable :: rdispls(:), recvcnts(:)
1002 real(real64), allocatable :: sendbuffer(:, :), recvbuffer(:, :)
1003
1004 push_sub_with_profile(broadcast_occupation)
1005
1006 assert(istart <= iend)
1007 assert(ubound(occ, dim = 1) >= iend)
1008 assert(ubound(occ, dim = 2) == kpt%nglobal())
1009 assert(.not. parstate)
1010
1011 if (kpt%parallel) then
1012 act_nst = iend - istart + 1
1013
1014 safe_allocate(recvcnts(1:kpt%mpi_grp%size))
1015 safe_allocate(rdispls(1:kpt%mpi_grp%size))
1016 safe_allocate(sendbuffer(1:act_nst, kpt%nlocal()))
1017 safe_allocate(recvbuffer(1:act_nst, 1:kpt%nglobal()))
1018
1019 incount = act_nst * kpt%nlocal()
1020 recvcnts(:) = act_nst * kpt%num(:)
1021 sendbuffer(1:act_nst, 1:kpt%nlocal()) = occ(istart:iend, kpt%start:kpt%end)
1022
1023 call mpi_displacements(recvcnts, rdispls)
1024 ! send buffer and receive buffer can not be the same address
1025 ! recvbuffer should be contiguous in memory
1026 call kpt%mpi_grp%allgatherv(sendbuffer, incount, mpi_double_precision, &
1027 recvbuffer, recvcnts, rdispls, mpi_double_precision)
1028
1029 occ(istart:iend, 1:kpt%nglobal()) = recvbuffer(1:act_nst, 1:kpt%nglobal())
1030
1031 safe_deallocate_a(sendbuffer)
1032 safe_deallocate_a(recvbuffer)
1033 safe_deallocate_a(recvcnts)
1034 safe_deallocate_a(rdispls)
1035 end if
1036
1037 pop_sub_with_profile(broadcast_occupation)
1038
1039 end subroutine broadcast_occupation
1040
1056 subroutine dissipation(hm, st, namespace, nresd_k, dt, dmp, rho_mat_k)
1057 type(hamiltonian_elec_t), intent(in) :: hm
1058 type(states_elec_t), intent(in) :: st
1059 type(namespace_t), intent(in) :: namespace
1060 integer, intent(in) :: nresd_k(:)
1061 real(real64), intent(in) :: dt
1062 type(dmp_t), intent(inout) :: dmp
1063 complex(real64), intent(inout) :: rho_mat_k(:, :, :)
1064
1065 integer :: act_nst
1066
1067 push_sub_with_profile(dissipation)
1068
1069 act_nst = dmp%iend - dmp%istart + 1
1070
1071 assert(ubound(nresd_k, dim = 1) == st%d%kpt%nlocal())
1072 assert(ubound(rho_mat_k, dim = 1) == 2*act_nst)
1073 assert(ubound(rho_mat_k, dim = 2) == 2*act_nst)
1074 assert(ubound(rho_mat_k, dim = 3) == st%d%kpt%nlocal())
1075
1076 if (dmp%calculation_mode == option__tddmpropagation__master_equation) then
1077 select case (dmp%strategy)
1078 case (1)
1079 call lindblad_uniform(dmp, st%d%kpt, nresd_k, dt, rho_mat_k)
1080 case (2)
1081 call lindblad_2times(dmp, st%d%kpt, nresd_k, dt, rho_mat_k)
1082 case (3)
1083 call lindblad_from_epw(dmp, hm, st%d%kpt, st%system_grp, namespace, nresd_k, dt, rho_mat_k)
1084 end select
1085 else if (dmp%calculation_mode == option__tddmpropagation__collision_integral) then
1086 call collision_from_epw(dmp, hm, st%d%kpt, st%system_grp, namespace, nresd_k, dt, rho_mat_k)
1087 end if
1088
1089 pop_sub_with_profile(dissipation)
1090
1091 end subroutine dissipation
1092
1097 subroutine lindblad_uniform(dmp, kpt, nresd_k, dt, rho_mat_k)
1098 type(dmp_t), intent(in) :: dmp
1099 type(distributed_t), intent(in) :: kpt
1100 integer, intent(in) :: nresd_k(:)
1101 real(real64), intent(in) :: dt
1102 complex(real64), intent(inout) :: rho_mat_k(:, :, :)
1103
1104 real(real64) :: coeff
1105 real(real64), allocatable :: rtrans(:, :)
1106 complex(real64), allocatable :: rho_in(:, :), rho_out(:, :), rho_res(:, :), rho_tmp(:, :)
1107 integer :: iorder, nst, ik, ik_, nresd, act_nst
1108 integer, parameter :: norder = 4
1109
1110 push_sub_with_profile(lindblad_uniform)
1111
1112 nst = dmp%adiabatic_st%nst
1113 act_nst = dmp%iend - dmp%istart + 1
1114
1115 ! lindblad operate on the density matrix
1116 safe_allocate(rtrans(1:act_nst, 1:act_nst))
1117 safe_allocate(rho_in(1:2*act_nst, 1:2*act_nst))
1118 safe_allocate(rho_out(1:2*act_nst, 1:2*act_nst))
1119 safe_allocate(rho_res(1:2*act_nst, 1:2*act_nst))
1120
1121 do ik = kpt%start, kpt%end
1122 ik_ = ik - kpt%start + 1
1123 nresd = nresd_k(ik_)
1124
1125 call transition_rate_uniform(dmp%uniform, dmp%adiabatic_st, dmp%istart, dmp%iend, ik, rtrans)
1126
1127 rho_res = 0.0_real64
1128 rho_in(1:2*act_nst, 1:2*act_nst) = rho_mat_k(1:2*act_nst, 1:2*act_nst, ik_)
1129
1130 coeff = m_one
1131 do iorder = 1, norder-1
1132
1133 call lindblad_operator_uniform(nresd, dmp%istart, dmp%iend, rtrans, rho_in, rho_out)
1134
1135 coeff = coeff * dt / iorder
1136 rho_res = rho_res + coeff * rho_out
1137 ! swap the pointer between rho_in and rho_out, so new rho_in is current rho_out,
1138 ! and new rho_out is the prior input that will get overwritten
1139 call move_alloc(rho_in, rho_tmp)
1140 call move_alloc(rho_out, rho_in)
1141 call move_alloc(rho_tmp, rho_out)
1142 end do
1143 ! iorder == norder
1144 call lindblad_operator_uniform(nresd, dmp%istart, dmp%iend, rtrans, rho_in, rho_out)
1145 coeff = coeff * dt / norder
1146 rho_res = rho_res + coeff * rho_out
1147
1148 rho_mat_k(1:2*act_nst, 1:2*act_nst, ik_) = rho_mat_k(1:2*act_nst, 1:2*act_nst, ik_) + rho_res
1149 end do
1150
1151 safe_deallocate_a(rho_in)
1152 safe_deallocate_a(rho_out)
1153 safe_deallocate_a(rtrans)
1154 safe_deallocate_a(rho_res)
1155
1156 pop_sub_with_profile(lindblad_uniform)
1157
1158 end subroutine lindblad_uniform
1159
1164 subroutine transition_rate_uniform(uniform, ad_st, istart, iend, ik, rtrans)
1165 real(real64), contiguous, intent(in) :: uniform(:)
1166 type(states_elec_t), intent(in) :: ad_st
1167 integer, intent(in) :: istart
1168 integer, intent(in) :: iend
1169 integer, intent(in) :: ik
1170 real(real64), contiguous, intent(out) :: rtrans(:, :)
1171
1172 integer :: ist, jst, act_nst
1173 real(real64) :: rate_character, omega, inv_omega, nph, delta_e
1174 real(real64), parameter :: small_e = 0.002_real64/(m_two*p_ry), large_e = 0.5_real64/(m_two*p_ry)
1175 real(real64) :: unocc_ist, unocc_jst
1176
1177 push_sub(transition_rate_uniform)
1178
1179 act_nst = iend - istart + 1
1180
1181 assert(ubound(rtrans, dim = 1) == act_nst)
1182 assert(ubound(rtrans, dim = 2) == act_nst)
1183
1184 rate_character = 1 / uniform(1)
1185 omega = units_to_atomic(unit_kelvin, uniform(2))
1186 inv_omega = 1.0_real64 / max(omega, 1.0e-12_real64)
1187
1188 rtrans = m_zero
1189 ! rtrans(ist, jst) is the transition rate from jst to ist
1190 do ist = istart, iend
1191 unocc_ist = 1.0_real64 - ad_st%occ(ist, ik) / ad_st%smear%el_per_state
1192
1193 do jst = ist + 1, iend
1194 delta_e = ad_st%eigenval(jst, ik) - ad_st%eigenval(ist, ik)
1195 if (delta_e < small_e) cycle
1196
1197 if (delta_e < large_e) then
1198 nph = 1.0_real64/(exp(delta_e*inv_omega) - 1.0_real64)
1199 else
1200 nph = m_zero
1201 end if
1202 unocc_jst = 1.0_real64 - ad_st%occ(jst, ik) / ad_st%smear%el_per_state
1203
1204 rtrans(ist-istart+1, jst-istart+1) = merge(rate_character * unocc_ist * (nph + 1), m_zero, unocc_ist > m_zero)
1205 rtrans(jst-istart+1, ist-istart+1) = merge(rate_character * unocc_jst * nph, m_zero, unocc_jst > m_zero)
1206 end do
1207 end do
1208
1210
1211 end subroutine transition_rate_uniform
1212
1218 subroutine lindblad_operator_uniform(nresd, istart, iend, rtrans, den_mat, l_mat)
1219 integer, intent(in) :: nresd
1220 integer, intent(in) :: istart
1221 integer, intent(in) :: iend
1222 real(real64), contiguous, intent(in) :: rtrans(:, :)
1223 complex(real64), contiguous, intent(in) :: den_mat(:, :)
1224 complex(real64), contiguous, intent(out) :: l_mat(:, :)
1225
1226 integer :: ist, jst, lst, act_nst
1227
1228 push_sub_with_profile(lindblad_operator_uniform)
1229
1230 act_nst = iend - istart + 1
1231
1232 assert(ubound(rtrans, dim = 1) == act_nst)
1233 assert(ubound(rtrans, dim = 2) == act_nst)
1234 assert(ubound(den_mat, dim = 1) == 2*act_nst)
1235 assert(ubound(den_mat, dim = 2) == 2*act_nst)
1236 assert(ubound(l_mat, dim = 1) == 2*act_nst)
1237 assert(ubound(l_mat, dim = 2) == 2*act_nst)
1238
1239 l_mat = 0.0_real64
1240
1241 do ist = 1, act_nst
1242 do jst = 1, act_nst
1243 if (ist == jst) cycle
1244 do lst = 1, act_nst+nresd
1245 l_mat(ist, lst) = l_mat(ist, lst) - m_half * rtrans(jst, ist) * den_mat(ist, lst)
1246 l_mat(lst, ist) = l_mat(lst, ist) - m_half * rtrans(jst, ist) * den_mat(lst, ist)
1247 end do
1248 l_mat(jst, jst) = l_mat(jst, jst) + rtrans(jst, ist) * den_mat(ist, ist)
1249 end do
1250 end do
1251
1252 pop_sub_with_profile(lindblad_operator_uniform)
1253
1254 end subroutine lindblad_operator_uniform
1255
1263 subroutine lindblad_2times(dmp, kpt, nresd_k, dt, rho_mat_k)
1264 type(dmp_t), intent(in) :: dmp
1265 type(distributed_t), intent(in) :: kpt
1266 integer, intent(in) :: nresd_k(:)
1267 real(real64), intent(in) :: dt
1268 complex(real64), intent(inout) :: rho_mat_k(:, :, :)
1269
1270 real(real64) :: decay_T1, decay_T2
1271 integer :: ist, jst, ik, ik_, nresd, act_nst
1272
1273 push_sub_with_profile(lindblad_2times)
1274
1275 act_nst = dmp%iend - dmp%istart + 1
1276
1277 decay_t1 = exp(-dt / dmp%tmodel(1))
1278 decay_t2 = exp(-dt / dmp%tmodel(2))
1279
1280 do ik = kpt%start, kpt%end
1281 ik_ = ik - kpt%start + 1
1282 nresd = nresd_k(ik_)
1283
1284 do ist = dmp%istart, dmp%iend
1285 rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) = dmp%occ_gs(ist, ik_) + &
1286 (rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) - dmp%occ_gs(ist, ik_)) * decay_t1
1287 end do
1288 do ist = act_nst+1, act_nst+nresd
1289 rho_mat_k(ist, ist, ik_) = rho_mat_k(ist, ist, ik_) * decay_t1
1290 end do
1291 do ist = 1, act_nst+nresd
1292 do jst = ist+1, act_nst+nresd
1293 rho_mat_k(jst, ist, ik_) = rho_mat_k(jst, ist, ik_) * decay_t2
1294 rho_mat_k(ist, jst, ik_) = rho_mat_k(ist, jst, ik_) * decay_t2
1295 end do
1296 end do
1297 end do
1298
1299 pop_sub_with_profile(lindblad_2times)
1300 end subroutine lindblad_2times
1301
1305 subroutine lindblad_from_epw(dmp, hm, kpt, system_grp, namespace, nresd_k, dt, rho_mat_k)
1306 type(dmp_t), intent(inout) :: dmp
1307 type(hamiltonian_elec_t), intent(in) :: hm
1308 type(distributed_t), intent(in) :: kpt
1309 type(mpi_grp_t), intent(in) :: system_grp
1310 type(namespace_t), intent(in) :: namespace
1311 integer, intent(in) :: nresd_k(:)
1312 real(real64), intent(in) :: dt
1313 complex(real64), intent(inout) :: rho_mat_k(:, :, :)
1314
1315 real(real64) :: coeff
1316 real(real64), allocatable :: rho_diag(:, :)
1317 complex(real64), allocatable :: rho_in(:, :, :), rho_out(:, :, :), rho_tmp(:, :, :)
1318 integer, parameter :: norder = 4
1319 integer :: ist, iorder, ik, ik_, nik, act_nst
1320
1321 push_sub_with_profile(lindblad_from_epw)
1322
1323 nik = dmp%adiabatic_st%nik
1324 act_nst = dmp%iend - dmp%istart + 1
1325
1326 call dmp%update_trans_rate(hm, system_grp, namespace)
1327
1328 ! the diagonal elements of L\rho is initialized to occupation
1329 ! SAFE_ALLOCATE_SOURCE_A(rho_diag, dmp%adiabatic_st%occ)
1330 safe_allocate(rho_diag(1:act_nst, nik))
1331 rho_diag(1:act_nst, 1:nik) = dmp%adiabatic_st%occ(dmp%istart:dmp%iend, 1:nik)
1332
1333 ! L_D[rho_in] = rho_out
1334 safe_allocate_source(rho_in, rho_mat_k)
1335 safe_allocate(rho_out(1:2*act_nst, 1:2*act_nst, 1:kpt%nlocal()))
1336
1337 ! dimensition of rho_out should be modified later
1338 coeff = 1.0_real64
1339 do iorder = 1, norder - 1
1340
1341 coeff = coeff * dt / iorder
1342
1343 do ik = kpt%start, kpt%end
1344 ik_ = ik - kpt%start + 1
1345
1346 call lindblad_operator_epw(dmp, ik, hm%kpoints%nik_skip, nresd_k(ik_), rho_diag, rho_in(:, :, ik_), rho_out(:, :, ik_))
1347
1348 call lalg_axpy(2*act_nst, 2*act_nst, coeff, rho_out(:, :, ik_), rho_mat_k(:, :, ik_))
1349 end do
1350
1351 ! update rho_diag independently
1352 do ik = kpt%start, kpt%end
1353 ik_ = ik - kpt%start + 1
1354 do ist = dmp%estart, dmp%eend
1355 rho_diag(ist-dmp%istart+1, ik) = real(rho_out(ist-dmp%istart+1, ist-dmp%istart+1, ik_))
1356 end do
1357 end do
1358 ! broadcast occupation for all processes, modify later
1359 ! call broadcast_occupation(rho_diag, kpt, nst, dmp%adiabatic_st%parallel_in_states)
1360 call broadcast_occupation(rho_diag, kpt, dmp%adiabatic_st%parallel_in_states, &
1361 dmp%estart-dmp%istart+1, dmp%eend-dmp%istart+1)
1362
1363 ! swap the pointer between rho_in and rho_out, so new rho_in is current rho_out,
1364 ! and new rho_out is the prior input that will get overwritten
1365 call move_alloc(rho_in, rho_tmp)
1366 call move_alloc(rho_out, rho_in)
1367 call move_alloc(rho_tmp, rho_out)
1368 end do
1369
1370 ! iorder == norder
1371 coeff = coeff * dt / norder
1372
1373 do ik = kpt%start, kpt%end
1374 ik_ = ik - kpt%start + 1
1375
1376 call lindblad_operator_epw(dmp, ik, hm%kpoints%nik_skip, nresd_k(ik_), rho_diag, rho_in(:, :, ik_), rho_out(:, :, ik_))
1377
1378 call lalg_axpy(2*act_nst, 2*act_nst, coeff, rho_out(:, :, ik_), rho_mat_k(:, :, ik_))
1379 end do
1380
1381
1382 safe_deallocate_a(rho_in)
1383 safe_deallocate_a(rho_out)
1384 safe_deallocate_a(rho_diag)
1385
1386 pop_sub_with_profile(lindblad_from_epw)
1387 end subroutine lindblad_from_epw
1388
1398 subroutine collision_from_epw(dmp, hm, kpt, system_grp, namespace, nresd_k, dt, rho_mat_k)
1399 type(dmp_t), intent(inout) :: dmp
1400 type(hamiltonian_elec_t), intent(in) :: hm
1401 type(distributed_t), intent(in) :: kpt
1402 type(mpi_grp_t), intent(in) :: system_grp
1403 type(namespace_t), intent(in) :: namespace
1404 integer, intent(in) :: nresd_k(:)
1405 real(real64), intent(in) :: dt
1406 complex(real64), intent(inout) :: rho_mat_k(:, :, :)
1407
1408 real(real64) :: gam, gam_in, gam_out
1409 real(real64), allocatable :: gam_bnd(:)
1410 real(real64), parameter :: gthresh = 1.0e-8_real64
1411 integer :: ist, jst, ik, nresd, ik_, nik_skip, act_nst
1412
1413 push_sub_with_profile(collision_from_epw)
1414
1415 nik_skip = hm%kpoints%nik_skip
1416 act_nst = dmp%iend - dmp%istart + 1
1417
1418 safe_allocate(gam_bnd(2*dmp%adiabatic_st%nst))
1419
1420 call dmp%update_trans_rate(hm, system_grp, namespace)
1421
1422 ! off-diagonals
1423 do ik = kpt%start, kpt%end
1424 ik_ = ik - kpt%start + 1
1425 nresd = nresd_k(ik_)
1426
1427 ! pre-calculate gamma
1428 gam_bnd = 0.0_real64
1429 do ist = dmp%estart, dmp%eend
1430 call lifetime(dmp, ik, ist, nik_skip, gam_bnd(ist))
1431 end do
1432
1433 do ist = 1, act_nst + nresd
1434 do jst = ist + 1, act_nst + nresd
1435 gam = -(gam_bnd(ist+dmp%istart-1) + gam_bnd(jst+dmp%istart-1)) / 2.0_real64
1436
1437 ! damping
1438 rho_mat_k(jst, ist, ik_) = rho_mat_k(jst, ist, ik_) * exp(gam * dt)
1439 rho_mat_k(ist, jst, ik_) = conjg(rho_mat_k(jst, ist, ik_))
1440 end do
1441 end do
1442 end do
1443
1444 ! diagonals, \dot{f} = -gam_out * f + gam_in, gives analytical solution
1445 do ik = kpt%start, kpt%end
1446 ik_ = ik - kpt%start + 1
1447 do ist = dmp%estart, dmp%eend
1448 call get_gamma(dmp, ik, ist, nik_skip, gam_in, gam_out)
1449 if (gam_out * dt > gthresh) then
1450 rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) = rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) *&
1451 exp(-gam_out * dt) + (gam_in / gam_out) * (1.0_real64 - exp(-gam_out * dt))
1452 else
1453 ! when denominator divergent
1454 rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) = rho_mat_k(ist-dmp%istart+1, ist-dmp%istart+1, ik_) *&
1455 (1.0_real64 - gam_out * dt) + gam_in * dt
1456 end if
1457 end do
1458 end do
1459
1460 safe_deallocate_a(gam_bnd)
1461
1462 pop_sub_with_profile(collision_from_epw)
1463 end subroutine collision_from_epw
1464
1466 subroutine dm_propagation_update_trans_rate(this, hm, system_grp, namespace)
1467 class(dmp_t), intent(inout) :: this
1468 type(hamiltonian_elec_t), intent(in) :: hm
1469 type(mpi_grp_t), intent(in) :: system_grp
1470 type(namespace_t), intent(in) :: namespace
1471
1472 integer :: ia
1473
1474 push_sub_with_profile(dmp_propagation_update_trans_rate)
1475
1476 ia = get_vector_field_index(this, hm, namespace)
1477
1478 if (ia /= this%ia) then
1479 call iopar_read_trans_rate(ia, system_grp, namespace, this)
1480 this%ia = ia
1481 end if
1482
1483 pop_sub_with_profile(dmp_propagation_update_trans_rate)
1484
1486
1488 subroutine iopar_open_trans_rate(namespace, ions, hm, system_grp, dmp)
1489 type(namespace_t), intent(in) :: namespace
1490 type(ions_t), intent(in) :: ions
1491 type(hamiltonian_elec_t), intent(in) :: hm
1492 type(mpi_grp_t), intent(in) :: system_grp
1493 type(dmp_t), intent(inout) :: dmp
1494
1495 integer :: ierr, iostat, idim, idir, iqq, totq
1496 integer :: epw_nk(3), oct_nk(3)
1497 real(real64) :: oct_s(3), at(3,3)
1498
1499 push_sub(iopar_open_trans_rate)
1500
1501 ! metadata
1502 if (system_grp%is_root()) then
1503 open(newunit=dmp%iunit, file=trim(dmp%epw_file), form='unformatted', access='stream', status='old', &
1504 action='read', iostat=iostat)
1505 if (iostat /= 0) then
1506 dmp%iunit = -1
1507 write(message(1), '(a,a)') 'Error opening file: ', trim(dmp%epw_file)
1508 call messages_fatal(1, namespace=namespace)
1509 end if
1510 !
1511 read(dmp%iunit, iostat=ierr) iqq, totq, dmp%wnst, epw_nk(1:3), at, oct_nk(1:3), oct_s(1:3), dmp%astep(1:3), dmp%na(1:3)
1512 if (ierr /= 0) then
1513 write(message(1), '(a,a)') 'Error reading header from: ', trim(dmp%epw_file)
1514 call messages_fatal(1, namespace=namespace)
1515 end if
1516 !
1517 end if
1518
1519 call system_grp%bcast(dmp%wnst, 1, mpi_integer, 0)
1520 call system_grp%bcast(at, 9, mpi_double_precision, 0)
1521 call system_grp%bcast(oct_s, 3, mpi_double_precision, 0)
1522 call system_grp%bcast(dmp%astep, 3, mpi_double_precision, 0)
1523 call system_grp%bcast(dmp%na, 3, mpi_integer, 0)
1524 call system_grp%bcast(epw_nk, 3, mpi_integer, 0)
1525 call system_grp%bcast(oct_nk, 3, mpi_integer, 0)
1526
1527 if (any(oct_nk /= hm%kpoints%nik_axis)) then
1528 write(message(1), '(a, a)') 'Inconsistent k-point mesh in KPointsGrid and ', trim(dmp%epw_file)
1529 call messages_fatal(1, namespace=namespace)
1530 end if
1531 if (any(abs(oct_s - hm%kpoints%full%shifts(:, 1)) > m_epsilon)) then
1532 write(message(1), '(a, a)') 'Inconsistent k-point mesh shifts in KPointsGrid and ', trim(dmp%epw_file)
1533 call messages_fatal(1, namespace=namespace)
1534 end if
1535 !
1536 write(message(1), '(3(a,i0), a)') 'Info: Averaged transition rates obtained from a ', epw_nk(1), ' x ', &
1537 epw_nk(2), ' x ', epw_nk(3), ' EPW k-point mesh'
1538 call messages_info(1, namespace=namespace)
1539 !
1540 dmp%eend = dmp%estart + dmp%wnst - 1
1541 write(message(1), '(a, i0, a, i0)') 'Info: Damping band ', dmp%estart, ' - ', dmp%eend
1542 call messages_info(1, namespace=namespace)
1543 if (dmp%eend > dmp%iend) then
1544 write(message(1), '(a)') 'The highest damping band cannot exceed TDDMBandHighest.'
1545 call messages_fatal(1, namespace=namespace)
1546 end if
1547 !
1548 write(message(1),'(a)') ' EPW Lattice Vectors [1/alat]'
1549 do idim = 1, 3
1550 write(message(1+idim),'(3f12.6)') (at(idir, idim), idir = 1, 3)
1551 end do
1552 call messages_info(4, namespace=namespace)
1553 if (any(abs(at - ions%latt%rlattice_primitive) > m_epsilon)) then
1554 write(message(1),'(a)') 'Lattice settings are not fully consistent with those in EPW'
1555 call messages_warning(1, namespace=namespace)
1556 end if
1557
1558 call build_epw_kmap(namespace, hm%kpoints, dmp)
1560 ! initialize vector field grid index
1561 dmp%ia = -1
1562
1563 ! shared memory for transition rates
1564 dmp%num = int(product(oct_nk), kind=int64)**2 * int(dmp%wnst, kind=int64)**2
1565#ifdef HAVE_MPI
1566 ! create shared memory window and fill it only on root
1567 call create_intranode_communicator(system_grp, dmp%intranode_grp, dmp%internode_grp)
1568 ! We inline the logic of lmpi_create_shared_memory_window because single precision is not supported.
1569 call slmpi_create_shared_memory_window(dmp%num, dmp%intranode_grp, dmp%window_trans_rate, ave_trans)
1570#else
1571 safe_allocate(ave_trans(1:dmp%num))
1572#endif
1573
1574 pop_sub(iopar_open_trans_rate)
1575 end subroutine iopar_open_trans_rate
1576
1578 subroutine iopar_read_trans_rate(ia, system_grp, namespace, dmp)
1579 integer, intent(in) :: ia
1580 type(mpi_grp_t), intent(in) :: system_grp
1581 type(namespace_t), intent(in) :: namespace
1582 type(dmp_t), intent(inout) :: dmp
1583
1584 integer(int64), parameter :: header_bytes = 168 ! head info in binary file
1585 integer(int64), parameter :: epw_bytes = 4 ! single precision
1586 integer(int64) :: offset
1587 integer :: ierr
1588
1589 push_sub(iopar_read_trans_rate)
1590
1591 if (system_grp%is_root()) then
1592 ! single precision
1593 offset = header_bytes + int(ia - 1, kind=int64) * dmp%num * epw_bytes + 1_int64
1594 read(dmp%iunit, pos=offset, iostat=ierr) ave_trans
1595 if (ierr /= 0) then
1596 write(message(1), '(a,a)') 'Error reading transition rates from: ', trim(dmp%epw_file)
1597 call messages_fatal(1, namespace=namespace)
1598 end if
1599 end if
1600
1601#ifdef HAVE_MPI
1602 ! now broadcast the global arrays to local rank 0 on each node
1603 if (dmp%intranode_grp%rank == 0) then
1604 call dmp%internode_grp%bcast(ave_trans(1), dmp%num, mpi_real, 0)
1605 end if
1606 call lmpi_sync_shared_memory_window(dmp%window_trans_rate, dmp%intranode_grp)
1607#endif
1608
1609 pop_sub(iopar_read_trans_rate)
1610 end subroutine iopar_read_trans_rate
1611
1615 subroutine iopar_close_trans_rate(system_grp, dmp)
1616 type(mpi_grp_t), intent(in) :: system_grp
1617 type(dmp_t), intent(inout) :: dmp
1618
1619 push_sub(iopar_close_trans_rate)
1620
1621 safe_deallocate_a(dmp%kmap)
1622
1623 if (system_grp%is_root()) then
1624 close(dmp%iunit)
1625 end if
1626
1627#ifdef HAVE_MPI
1628 call lmpi_destroy_shared_memory_window(dmp%window_trans_rate)
1629 nullify(ave_trans)
1630#else
1631 safe_deallocate_p(ave_trans)
1632#endif
1633
1634 pop_sub(iopar_close_trans_rate)
1635
1636 end subroutine iopar_close_trans_rate
1637
1639 subroutine build_epw_kmap(namespace, kpoints, dmp)
1640 type(namespace_t), intent(in) :: namespace
1641 type(kpoints_t), intent(in) :: kpoints
1642 type(dmp_t), intent(inout) :: dmp
1643
1644 integer :: ik, idx, nik, nik_mp
1645 integer :: kidx_(3)
1646 real(real64) :: kred(3), kidx(3)
1647 real(real64), parameter :: tol = 1.0d-10
1648
1649 push_sub(build_epw_kmap)
1650
1651 nik = dmp%adiabatic_st%nik
1652 nik_mp = nik - kpoints%nik_skip
1653 safe_allocate(dmp%kmap(nik))
1654
1655 ! mp k-points
1656 dmp%kmap = nik_mp + 1
1657
1658 do ik = 1, nik
1659 ! Map reduced coordinate into an integer MP-grid coordinate
1660 kred = kpoints%get_point(ik, .false.)
1661 kidx = (kred + 0.5_real64) * real(kpoints%nik_axis, kind=real64) - kpoints%full%shifts(:, 1)
1662
1663 ! for MP k-points
1664 if (ik <= nik_mp) then
1665 if (any(abs(kidx - nint(kidx)) > tol)) then
1666 write(message(1), '(a)') 'K-point mesh is not compatible with EPW input'
1667 call messages_fatal(1, namespace=namespace)
1668 end if
1669 end if
1670
1671 ! Fold into central cell in EPW
1672 kidx_ = modulo(nint(kidx), kpoints%nik_axis)
1673 ! Flatten into a single, contiguous index
1674 idx = kidx_(1) * kpoints%nik_axis(2) * kpoints%nik_axis(3) + kidx_(2) * kpoints%nik_axis(3) + &
1675 kidx_(3) + 1
1676
1677 dmp%kmap(ik) = idx
1678 end do
1679
1680 ! sanity check
1681 assert(all(dmp%kmap <= nik_mp))
1682
1683 pop_sub(build_epw_kmap)
1684 end subroutine build_epw_kmap
1685
1687 function get_vector_field_index(dmp, hm, namespace) result(aidx)
1688 type(dmp_t), intent(in) :: dmp
1689 type(hamiltonian_elec_t), intent(in) :: hm
1690 type(namespace_t), intent(in) :: namespace
1691
1692 real(real64) :: ared(3), approx(3)
1693 integer :: apoint_idx(3)
1694 integer :: aidx, idim
1695
1696 push_sub(get_vector_field_index)
1697
1698 ! Find the nearest discrete vector field grid point on the EPW vector field mesh
1699 if (allocated(hm%hm_base%uniform_vector_potential)) then
1700 call kpoints_to_reduced(hm%ions%latt, hm%hm_base%uniform_vector_potential, ared)
1701 else
1702 ared = 0.0_real64
1703 end if
1704 do idim = 1, 3
1705 if (dmp%astep(idim) > m_zero) then
1706 apoint_idx(idim) = nint(ared(idim) / dmp%astep(idim))
1707 approx(idim) = apoint_idx(idim) * dmp%astep(idim)
1708 else
1709 apoint_idx(idim) = 0
1710 approx(idim) = 0.0_real64
1711 end if
1712 end do
1713 if (any(abs(apoint_idx) > dmp%na)) then
1714 write(message(1), '(a, 3F8.3)') 'Vector potential exceeds mesh range: ', ared
1715 call messages_warning(1, namespace=namespace)
1716 where (apoint_idx < -dmp%na)
1717 apoint_idx = -dmp%na
1718 end where
1719 where (apoint_idx > dmp%na)
1720 apoint_idx = dmp%na
1721 end where
1722 end if
1723 ! Get the flattened 1D index
1724 ! Step 1: Find the relative offset by subtracting the minimum index (-na).
1725 ! This shifts the range [-na, na] to an offset [0, 2*na].
1726 ! e.g., if range is [-2, 2], the offset for 1 is 1 - (-2) = 3.
1727 ! Step 2: Flatten the 3D offsets into 1D, and finally add 1 for Fortran 1-based indexing.
1728 aidx = (apoint_idx(1) + dmp%na(1)) * (2 * dmp%na(2) + 1) * (2 * dmp%na(3) + 1) + &
1729 (apoint_idx(2) + dmp%na(2)) * (2 * dmp%na(3) + 1) + &
1730 (apoint_idx(3) + dmp%na(3)) + 1
1731
1732 write(message(1), '(a, x, 3F7.3)') 'Approximated vector field damping grid:', approx
1733 call messages_info(1, namespace=namespace)
1734
1735 pop_sub(get_vector_field_index)
1736 end function get_vector_field_index
1737
1742 function get_trans_rate(dmp, nik_mp, jbnd, ibnd, k, kq, p_block) result(res)
1743 type(dmp_t), intent(in) :: dmp
1744 integer, intent(in) :: nik_mp
1745 integer, intent(in) :: jbnd
1746 integer, intent(in) :: ibnd
1747 integer, intent(in) :: k
1748 integer, intent(in) :: kq
1749 logical, optional, intent(in) :: p_block
1750
1751 real(real64) :: unocc, res
1752 integer :: k_, kq_
1753 integer(int64) :: idx
1754
1755 push_sub(get_trans_rate)
1756
1757 k_ = dmp%kmap(k)
1758 kq_ = dmp%kmap(kq)
1759 ! Flatten 4D transition rate index to 1D: (kq, k, ibnd, jbnd) -> idx
1760 ! Matrix dimensions are [nik_mp, nik_mp, wnst, wnst]
1761 ! The layout follows the hierarchy: kq is the slowest index, jbnd is the fastest.
1762 idx = int(kq_-1, kind=int64) * int(nik_mp, kind=int64) * int(dmp%wnst, kind=int64)**2 + &
1763 int((k_-1) * dmp%wnst**2, kind=int64) + &
1764 int((ibnd-dmp%estart)*dmp%wnst + (jbnd-dmp%estart) + 1, kind=int64)
1765
1766 assert(idx >= 1 .and. idx <= dmp%num)
1767
1768 res = real(ave_trans(idx), kind=real64)
1769 ! Pauli blocking
1770 if (optional_default(p_block, .true.)) then
1771 unocc = 1.0_real64 - dmp%adiabatic_st%occ(jbnd, kq) / dmp%adiabatic_st%smear%el_per_state
1772 res = res * max(unocc, 0.0_real64)
1773 end if
1774
1775 pop_sub(get_trans_rate)
1776 end function get_trans_rate
1777
1785 subroutine lindblad_operator_epw(dmp, ik, nik_skip, nresd, rho_diag, den_mat, l_mat)
1786 type(dmp_t), intent(in) :: dmp
1787 integer, intent(in) :: ik
1788 integer, intent(in) :: nik_skip
1789 integer, intent(in) :: nresd
1790 real(real64), contiguous, intent(in) :: rho_diag(:, :)
1791 complex(real64), contiguous, intent(in) :: den_mat(:, :)
1792 complex(real64), contiguous, intent(out) :: l_mat(:, :)
1793
1794 integer :: lst, nst, nik_mp, ikq, ibnd, jbnd, act_nst
1795 real(real64) :: tr
1796 push_sub(lindblad_operator_epw)
1797
1798 nst = dmp%adiabatic_st%nst
1799 nik_mp = dmp%adiabatic_st%nik - nik_skip
1800 act_nst = dmp%iend - dmp%istart + 1
1801
1802 assert(ubound(rho_diag, dim = 1) == act_nst)
1803 assert(ubound(rho_diag, dim = 2) == dmp%adiabatic_st%nik)
1804 assert(ubound(den_mat, dim = 1) == 2*act_nst)
1805 assert(ubound(den_mat, dim = 2) == 2*act_nst)
1806 assert(ubound(l_mat, dim = 1) == 2*act_nst)
1807 assert(ubound(l_mat, dim = 2) == 2*act_nst)
1808
1809 l_mat = 0.0_real64
1810
1811 ! there are two types of damping: 1. mp-mp k-grid scattering; 2. highsympath-mp k-grid scattering
1812 ! in both case, ikq is the mp grid.
1813 do ikq = 1, nik_mp
1814 do jbnd = dmp%estart, dmp%eend
1815 do ibnd = dmp%estart, dmp%eend
1816
1817 tr = get_trans_rate(dmp, nik_mp, jbnd, ibnd, ik, ikq, p_block=.true.)
1818 do lst = 1, act_nst+nresd
1819 l_mat(ibnd-dmp%istart+1, lst) = l_mat(ibnd-dmp%istart+1, lst) - m_half * tr * den_mat(ibnd-dmp%istart+1, lst)
1820 l_mat(lst, ibnd-dmp%istart+1) = l_mat(lst, ibnd-dmp%istart+1) - m_half * tr * den_mat(lst, ibnd-dmp%istart+1)
1821 end do
1822 l_mat(ibnd-dmp%istart+1, ibnd-dmp%istart+1) = l_mat(ibnd-dmp%istart+1, ibnd-dmp%istart+1) + &
1823 get_trans_rate(dmp, nik_mp, ibnd, jbnd, ikq, ik, p_block=.true.) * rho_diag(jbnd-dmp%istart+1, ikq)
1824 end do
1825 end do
1826 end do
1828 pop_sub(lindblad_operator_epw)
1829
1830 end subroutine lindblad_operator_epw
1831
1836 subroutine lifetime(dmp, ik, ibnd, nik_skip, gam)
1837 type(dmp_t), intent(in) :: dmp
1838 integer, intent(in) :: ik
1839 integer, intent(in) :: ibnd
1840 integer, intent(in) :: nik_skip
1841 real(real64), intent(out) :: gam
1842
1843 integer :: nik_mp, ikq, jbnd
1844 real(real64) :: tr
1845 push_sub(lifetime)
1846
1847 assert(ibnd >= dmp%estart .and. ibnd <= dmp%eend)
1848 nik_mp = dmp%adiabatic_st%nik - nik_skip
1849
1850 ! there are two types of damping: 1. mp-mp k-grid scattering; 2. highsympath-mp k-grid scattering
1851 ! in both case, ikq is the mp grid.
1852 gam = 0.0_real64
1853 do ikq = 1, nik_mp
1854 do jbnd = dmp%estart, dmp%eend
1855 tr = get_trans_rate(dmp, nik_mp, jbnd, ibnd, ik, ikq, p_block=.true.)
1856 gam = gam + tr
1857 tr = get_trans_rate(dmp, nik_mp, ibnd, jbnd, ikq, ik, p_block=.false.)
1858 gam = gam + tr * dmp%adiabatic_st%occ(jbnd, ikq) / dmp%adiabatic_st%smear%el_per_state
1859 end do
1860 end do
1861
1862 pop_sub(lifetime)
1863
1864 end subroutine lifetime
1865
1876 subroutine get_gamma(dmp, ik, ibnd, nik_skip, gam_in, gam_out)
1877 type(dmp_t), intent(in) :: dmp
1878 integer, intent(in) :: ik
1879 integer, intent(in) :: ibnd
1880 integer, intent(in) :: nik_skip
1881 real(real64), intent(out) :: gam_in
1882 real(real64), intent(out) :: gam_out
1883
1884 integer :: nik_mp, ikq, jbnd
1885 real(real64) :: tr
1886 push_sub(get_gamma)
1887
1888 assert(ibnd >= dmp%estart .and. ibnd <= dmp%eend)
1889 nik_mp = dmp%adiabatic_st%nik - nik_skip
1890
1891 ! there are two types of damping: 1. mp-mp k-grid scattering; 2. highsympath-mp k-grid scattering
1892 ! in both case, ikq is the mp grid.
1893 gam_in = 0.0_real64
1894 gam_out = 0.0_real64
1895 do ikq = 1, nik_mp
1896 do jbnd = dmp%estart, dmp%eend
1897 tr = get_trans_rate(dmp, nik_mp, jbnd, ibnd, ik, ikq, p_block=.true.)
1898 gam_out = gam_out + tr
1899 tr = get_trans_rate(dmp, nik_mp, ibnd, jbnd, ikq, ik, p_block=.true.)
1900 gam_in = gam_in + tr * dmp%adiabatic_st%occ(jbnd, ikq)
1901 end do
1902 end do
1903
1904 pop_sub(get_gamma)
1905
1906 end subroutine get_gamma
1907
1923 subroutine update_st(dmp, ik, gr, namespace, nresd, overlap_ad_ks, overlap_resd_ks, nrm2_tdks, resd, st, rho_mat, pop)
1924 type(dmp_t), intent(inout) :: dmp
1925 integer, intent(in) :: ik
1926 type(grid_t), intent(in) :: gr
1927 type(namespace_t), intent(in) :: namespace
1928 integer, intent(in) :: nresd
1929 complex(real64), contiguous, intent(in) :: overlap_ad_ks(:, :)
1930 complex(real64), contiguous, intent(in) :: overlap_resd_ks(:, :)
1931 real(real64), contiguous, intent(in) :: nrm2_tdks(:)
1932 type(states_elec_t), intent(inout) :: resd
1933 type(states_elec_t), intent(inout) :: st
1934 complex(real64), contiguous, intent(inout) :: rho_mat(:, :)
1935 real(real64), intent(inout) :: pop
1936
1937 real(real64), allocatable :: occ_act(:)
1938 complex(real64), allocatable :: overlap_ad_resd(:, :), overlap_act(:, :)
1939 integer :: ist, jst, nst, istart, iend, act_nst
1940
1941 push_sub_with_profile(update_st)
1942
1943 nst = dmp%adiabatic_st%nst
1944 istart = dmp%istart
1945 iend = dmp%iend
1946 act_nst = iend - istart + 1
1947
1948 assert(ubound(overlap_ad_ks, dim = 1) == nst)
1949 assert(ubound(overlap_ad_ks, dim = 2) == nst)
1950 assert(ubound(overlap_resd_ks, dim = 1) == nst)
1951 assert(ubound(overlap_resd_ks, dim = 2) == nst)
1952 assert(ubound(rho_mat, dim = 1) == 2*act_nst)
1953 assert(ubound(rho_mat, dim = 2) == 2*act_nst)
1954 assert(is_hermitian(2*act_nst, rho_mat))
1955
1956 safe_allocate(occ_act(1:act_nst+nresd))
1957
1958 ! Pack the active blocks of the density matrix into a contiguous sub-matrix
1959 if (dmp%othn) then
1960 call lalg_eigensolve(act_nst+nresd, rho_mat, occ_act)
1962 call check_set_positive(act_nst+nresd, act_nst, ik, namespace, occ_act)
1963 else
1964 assert(nresd == act_nst)
1965
1966 ! generalized eigenvalue problem
1967 safe_allocate(overlap_ad_resd(1:nst, 1:nst))
1968 safe_allocate(overlap_act(1:act_nst+nresd, 1:act_nst+nresd))
1969
1970 ! ad-ad block
1971 overlap_act = m_z0
1972 do ist = 1, act_nst
1973 overlap_act(ist, ist) = m_z1
1974 end do
1975
1976 ! ad-resd block
1977 call calc_overlap_state(ik, gr, dmp%adiabatic_st, resd, istart, iend, istart, iend, overlap_ad_resd)
1978 do jst = 1, act_nst
1979 do ist = 1, act_nst
1980 overlap_act(ist, act_nst+jst) = overlap_ad_resd(ist+istart-1, jst+istart-1)
1981 overlap_act(act_nst+jst, ist) = conjg(overlap_ad_resd(ist+istart-1, jst+istart-1))
1982 end do
1983 end do
1984
1985 ! resd-resd block
1986 ! _i<d | d>_j = S^{d,\psi}_{ij} - sum_k S^{\phi,\psi}_{kj} S^{d,\phi}_{ik}
1987 overlap_act(act_nst+1:act_nst+nresd, act_nst+1:act_nst+nresd) = overlap_resd_ks(istart:iend, istart:iend)
1988 call blas_gemm('C', 'N', nresd, nresd, act_nst, -m_z1, overlap_ad_resd(istart, istart), nst, &
1989 overlap_ad_ks(istart, istart), nst, m_z1, overlap_act(act_nst+1, act_nst+1), act_nst+nresd)
1990
1991 ! only the upper triangle of overlap is needed
1992 call lalg_geneigensolve(act_nst+nresd, rho_mat, overlap_act, occ_act, preserve_mat=.false.)
1993
1994 call check_set_positive(act_nst+nresd, act_nst, ik, namespace, occ_act)
1995
1996 safe_deallocate_a(overlap_ad_resd)
1997 safe_deallocate_a(overlap_act)
1998
1999 end if
2000
2001 if (dmp%unitary_transform) then
2002 call update_wfc_occ_procrustes(ik, gr, istart, iend, nresd, dmp%adiabatic_st, resd, overlap_ad_ks, overlap_resd_ks, &
2003 nrm2_tdks, occ_act, rho_mat, st, pop)
2004 else
2005 call update_wfc_occ(ik, gr, istart, iend, nresd, dmp%adiabatic_st, resd, occ_act, rho_mat, st, pop)
2006 end if
2007
2008 pop = pop + (sum(st%occ(1:istart-1,ik) * nrm2_tdks(1:istart-1)) + &
2009 sum(st%occ(iend+1:nst,ik) * nrm2_tdks(iend+1:nst))) * st%kweights(ik)
2010
2011 safe_deallocate_a(occ_act)
2012
2013 pop_sub_with_profile(update_st)
2014
2015 end subroutine update_st
2016
2022 subroutine check_set_positive(locc, npos, ik, namespace, occ)
2023 integer, intent(in) :: locc
2024 integer, intent(in) :: npos
2025 integer, intent(in) :: ik
2026 type(namespace_t), intent(in) :: namespace
2027 real(real64), intent(inout) :: occ(:)
2028
2029 real(real64), parameter :: small_eig = 1.0e-13_real64
2030 real(real64) :: occ_min
2031 integer :: i, istart
2032
2033 assert(ubound(occ, dim = 1) == locc)
2034
2035 istart = locc - npos + 1
2036 occ_min = occ(istart)
2037
2038 ! Single-pass memory traversal: find the minimum and floor negative values in-place
2039 do i = istart, locc
2040 if (occ(i) < occ_min) occ_min = occ(i)
2041 if (occ(i) < 0.0_real64) occ(i) = 0.0_real64
2042 end do
2043
2044 ! Abort if unphysical negative eigenvalues exceed the acceptable noise threshold
2045 if (occ_min < -small_eig) then
2046 write(message(1), '(a, E9.2, a, I0)') 'Density matrix has negative eigenvalues of ', occ_min, ' at ik = ', ik
2047 call messages_fatal(1, namespace=namespace)
2048 end if
2049 end subroutine check_set_positive
2050
2056 subroutine update_wfc_occ(ik, gr, istart, iend, nresd, ad_st, resd, occ, v_mat, st, pop)
2057 integer, intent(in) :: ik
2058 type(grid_t), intent(in) :: gr
2059 integer, intent(in) :: istart
2060 integer, intent(in) :: iend
2061 integer, intent(in) :: nresd
2062 type(states_elec_t), intent(in) :: ad_st
2063 type(states_elec_t), intent(in) :: resd
2064 real(real64), contiguous, intent(in) :: occ(:)
2065 complex(real64), contiguous, intent(in) :: v_mat(:, :)
2066 type(states_elec_t), intent(inout) :: st
2067 real(real64), intent(inout) :: pop
2068
2069 complex(real64), allocatable :: psi_j(:, :), phi(:, :)
2070 integer :: i, j, ib, i_minst, i_maxst, act_nst
2071
2072 push_sub_with_profile(update_wfc_occ)
2073
2074 act_nst = iend - istart + 1
2075
2076 assert(ubound(v_mat, dim = 1) == 2*act_nst)
2077 assert(ubound(v_mat, dim = 2) == 2*act_nst)
2078
2079 safe_allocate(psi_j(1:gr%np, st%d%dim))
2080 safe_allocate(phi(1:gr%np, st%d%dim))
2081
2082 do j = act_nst+nresd, nresd+1, -1
2083 psi_j = (0.0_real64, 0.0_real64)
2084 ! ad block
2085 do ib = ad_st%group%block_start, ad_st%group%block_end
2086 i_minst = states_elec_block_min(ad_st, ib)
2087 i_maxst = states_elec_block_max(ad_st, ib)
2088 if (i_minst >= istart .and. i_maxst <= iend) then
2089 call zbatch_axpy_function(gr%np, v_mat(i_minst-istart+1:i_maxst-istart+1, j), &
2090 ad_st%group%psib(ib, ik), psi_j)
2091 else
2092 do i = max(i_minst, istart), min(i_maxst, iend)
2093 call states_elec_get_state(ad_st, gr, i, ik, phi)
2094 call lalg_axpy(gr%np, ad_st%d%dim, v_mat(i-istart+1, j), phi, psi_j)
2095 end do
2096 end if
2097 end do
2098 ! resd block
2099 if (nresd > 0) then
2100 do ib = resd%group%block_start, resd%group%block_end
2101 i_minst = states_elec_block_min(resd, ib)
2102 i_maxst = states_elec_block_max(resd, ib)
2103 if (i_minst >= istart .and. i_maxst <= istart+nresd-1) then
2104 call zbatch_axpy_function(gr%np, v_mat(act_nst+i_minst-istart+1:act_nst+i_maxst-istart+1, j), &
2105 resd%group%psib(ib, ik), psi_j)
2106 else
2107 do i = max(i_minst, istart), min(i_maxst, istart+nresd-1)
2108 call states_elec_get_state(resd, gr, i, ik, phi)
2109 call lalg_axpy(gr%np, resd%d%dim, v_mat(act_nst+i-istart+1, j), phi, psi_j)
2110 end do
2111 end if
2112 end do
2113 end if
2114
2115 ! reset TDKS state
2116 call states_elec_set_state(st, gr, act_nst+nresd+istart-j, ik, psi_j)
2117 end do
2118
2119 ! eigenvalues in ascending order, so inverse
2120 st%occ(istart:iend, ik) = occ(act_nst+nresd:nresd+1:-1)
2121 pop = pop + sum(st%occ(istart:iend, ik)) * st%kweights(ik)
2122
2123 safe_deallocate_a(psi_j)
2124 safe_deallocate_a(phi)
2125 pop_sub_with_profile(update_wfc_occ)
2126 end subroutine update_wfc_occ
2127
2128
2143 subroutine update_wfc_occ_procrustes(ik, gr, istart, iend, nresd, ad_st, resd, overlap_ad_ks, overlap_resd_ks, &
2144 nrm2_tdks, occ_tilde, v_mat, st, pop)
2145 integer, intent(in) :: ik
2146 type(grid_t), intent(in) :: gr
2147 integer, intent(in) :: istart
2148 integer, intent(in) :: iend
2149 integer, intent(in) :: nresd
2150 type(states_elec_t), intent(in) :: ad_st
2151 type(states_elec_t), intent(in) :: resd
2152 complex(real64), contiguous, intent(in) :: overlap_ad_ks(:, :)
2153 complex(real64), contiguous, intent(in) :: overlap_resd_ks(:, :)
2154 real(real64), contiguous, intent(in) :: nrm2_tdks(:)
2155 real(real64), contiguous, intent(in) :: occ_tilde(:)
2156 complex(real64), contiguous, intent(inout) :: v_mat(:, :)
2157 type(states_elec_t), intent(inout) :: st
2158 real(real64), intent(inout) :: pop
2159
2160 integer :: ist, jst, ib, i_minst, i_maxst, nst, act_nst
2161 complex(real64), allocatable :: overlap_procrus(:, :), uproj(:, :), utrans(:, :)
2162 complex(real64), allocatable :: uu(:, :), vt(:, :)
2163 complex(real64), allocatable :: psi(:, :), phi(:, :)
2164 real(real64), parameter :: small_occ = 5.0e-15_real64 ! for those zero occupations, assume them a small quantity
2165 real(real64) :: sg_values(1:iend-istart+1), rocc_tilde(1:iend-istart+1+nresd), rocc(1:iend-istart+1)
2166 real(real64) :: qtot_transform, nrm2, occ
2167
2168 push_sub_with_profile(update_wfc_occ_procrustes)
2169
2170 nst = ad_st%nst
2171 act_nst = iend - istart + 1
2172
2173 assert(istart <= iend)
2174 assert(ubound(overlap_ad_ks, dim = 1) == nst)
2175 assert(ubound(overlap_ad_ks, dim = 2) == nst)
2176 assert(ubound(overlap_resd_ks, dim = 1) == nst)
2177 assert(ubound(overlap_resd_ks, dim = 2) == nst)
2178 assert(ubound(nrm2_tdks, dim = 1) == nst)
2179 assert(ubound(occ_tilde, dim = 1) == act_nst+nresd)
2180 assert(ubound(v_mat, dim = 1) == 2*act_nst)
2181 assert(ubound(v_mat, dim = 2) == 2*act_nst)
2182
2183 ! set rocc for both TDKS and new wfcs. For those zero occupations, set them a small quantity
2184 rocc_tilde(1:act_nst+nresd) = sqrt(max(occ_tilde(1:act_nst+nresd), small_occ))
2185 rocc(1:act_nst) = sqrt(max(st%occ(istart:iend, ik), small_occ))
2186
2187 safe_allocate(overlap_procrus(1:act_nst+nresd, 1:act_nst))
2188
2189 ! Procrustes Overlap: S \propto (C_{top})^\dagger S_{ad\_ks} + (C_{bot})^\dagger S_{resd\_ks}
2190 ! Computed via in-place BLAS GEMM accumulation ('C' for conjugate transpose),
2191 ! avoiding the temporary memory allocation and copy overhead of native matmul.
2192 call blas_gemm('C', 'N', act_nst+nresd, act_nst, act_nst, m_z1, v_mat(1, 1), 2*act_nst, &
2193 overlap_ad_ks(istart, istart), nst, m_z0, overlap_procrus(1, 1), act_nst+nresd)
2194 call blas_gemm('C', 'N', act_nst+nresd, act_nst, nresd, m_z1, v_mat(1+act_nst, 1), 2*act_nst, &
2195 overlap_resd_ks(istart, istart), nst, m_z1, overlap_procrus(1, 1), act_nst+nresd)
2196 do jst = 1, act_nst
2197 do ist = 1, act_nst+nresd
2198 overlap_procrus(ist, jst) = overlap_procrus(ist, jst) * rocc_tilde(ist) * rocc(jst)
2199 end do
2200 end do
2201
2202 safe_allocate(uproj(1:act_nst+nresd, 1:act_nst))
2203 safe_allocate(uu(1:act_nst+nresd, 1:act_nst+nresd))
2204 safe_allocate(vt(1:act_nst, 1:act_nst))
2205
2206 call lalg_singular_value_decomp(act_nst+nresd, act_nst, overlap_procrus, uu, vt, sg_values)
2207 uproj = matmul(uu(:,1:act_nst), vt)
2208
2209 safe_deallocate_a(overlap_procrus)
2210 safe_deallocate_a(vt)
2211 safe_deallocate_a(uu)
2212
2213 safe_allocate(utrans(1:act_nst+nresd, 1:act_nst))
2214
2215 ! update transformation matrix
2216 do ist = 1, act_nst+nresd
2217 call blas_scal(2*act_nst, cmplx(rocc_tilde(ist), 0.0, real64), v_mat(1, ist), 1)
2218 end do
2219 ! utrans = matmul(v_mat(1:act_nst+nresd,1:act_nst+nresd), uproj)
2220 call blas_gemm('N', 'N', act_nst+nresd, act_nst, act_nst+nresd, m_z1, v_mat(1, 1), 2*act_nst, &
2221 uproj(1, 1), act_nst+nresd, m_z0, utrans(1, 1), act_nst+nresd)
2222
2223 safe_deallocate_a(uproj)
2224 safe_allocate(psi(1:gr%np, st%d%dim))
2225 safe_allocate(phi(1:gr%np, st%d%dim))
2226
2227 ! update state and occupations
2228 qtot_transform = 0.0_real64
2229 do jst = istart, iend
2230 psi = (0.0_real64, 0.0_real64)
2231 ! ad basis
2232 do ib = ad_st%group%block_start, ad_st%group%block_end
2233 i_minst = states_elec_block_min(ad_st, ib)
2234 i_maxst = states_elec_block_max(ad_st, ib)
2235 if (i_minst >= istart .and. i_maxst <= iend) then
2236 call zbatch_axpy_function(gr%np, utrans(i_minst-istart+1:i_maxst-istart+1, jst-istart+1), &
2237 ad_st%group%psib(ib, ik), psi, nst=i_maxst-i_minst+1)
2238 else
2239 do ist = max(i_minst, istart), min(i_maxst, iend)
2240 call states_elec_get_state(ad_st, gr, ist, ik, phi)
2241 call lalg_axpy(gr%np, ad_st%d%dim, utrans(ist-istart+1, jst-istart+1), phi, psi)
2242 end do
2243 end if
2244 end do
2245 ! resd basis
2246 do ib = resd%group%block_start, resd%group%block_end
2247 i_minst = states_elec_block_min(resd, ib)
2248 i_maxst = states_elec_block_max(resd, ib)
2249 if (i_minst >= istart .and. i_maxst <= istart+nresd-1) then
2250 call zbatch_axpy_function(gr%np, utrans(act_nst+i_minst-istart+1:act_nst+i_maxst-istart+1, jst-istart+1), &
2251 resd%group%psib(ib, ik), psi, nst=i_maxst-i_minst+1)
2252 else
2253 do ist = max(i_minst, istart), min(i_maxst, istart+nresd-1)
2254 call states_elec_get_state(resd, gr, ist, ik, phi)
2255 call lalg_axpy(gr%np, st%d%dim, utrans(act_nst+ist-istart+1, jst-istart+1), phi, psi)
2256 end do
2257 end if
2258 end do
2259 nrm2 = real(zmf_dotp(gr, st%d%dim, psi, psi, reduce = .true.), real64)
2260 qtot_transform = qtot_transform + nrm2
2261 occ = nrm2 / nrm2_tdks(jst)
2262 st%occ(jst, ik) = occ
2263 call lalg_scal(gr%np, st%d%dim, 1.0_real64/sqrt(occ), psi)
2264 call states_elec_set_state(st, gr, jst, ik, psi)
2265 end do
2266
2267 pop = pop + qtot_transform * st%kweights(ik)
2268
2269 safe_deallocate_a(utrans)
2270 safe_deallocate_a(psi)
2271 safe_deallocate_a(phi)
2272
2273 pop_sub_with_profile(update_wfc_occ_procrustes)
2274
2275 end subroutine update_wfc_occ_procrustes
2276
2278 logical function is_hermitian(n, mat)
2279 integer, intent(in) :: n
2280 complex(real64), intent(in) :: mat(:, :)
2281 real(real64), parameter :: tol = 1.0e-14_real64
2282
2283 assert(ubound(mat, dim=1) == n)
2284 assert(ubound(mat, dim=2) == n)
2285
2286 is_hermitian = maxval(abs(mat - transpose(conjg(mat)))) <= tol
2287 end function is_hermitian
2288
2290 subroutine td_write_dm_proj_basis(this, out_dm_proj_basis, iter)
2291 class(dmp_t), intent(in) :: this
2292 type(c_ptr), intent(inout) :: out_dm_proj_basis
2293 integer, intent(in) :: iter
2294
2295 character(len=80) :: aux
2296 integer :: incount, ik, n_offd
2297 integer, allocatable :: rdispls(:), recvcnts(:)
2298 complex(real64), allocatable :: rho_offd(:, :)
2299
2300 push_sub(td_write_dm_proj_basis)
2301
2302 if (iter == 0) then
2303 if (this%adiabatic_st%system_grp%is_root()) then
2304 call td_write_print_header_init(out_dm_proj_basis)
2305
2306 write(aux, '(a15,i8)') "# nspin ", this%adiabatic_st%d%nspin
2307 call write_iter_string(out_dm_proj_basis, aux)
2308 call write_iter_nl(out_dm_proj_basis)
2309
2310 write(aux, '(a15,i8)') "# nik ", this%adiabatic_st%nik
2311 call write_iter_string(out_dm_proj_basis, aux)
2312 call write_iter_nl(out_dm_proj_basis)
2313
2314 write(aux, '(a15,2i8)') "# istart, iend ", this%istart, this%iend
2315 call write_iter_string(out_dm_proj_basis, aux)
2316 call write_iter_nl(out_dm_proj_basis)
2317
2318 write(aux, '(a)') "# loop sequence: "
2319 call write_iter_string(out_dm_proj_basis, aux)
2320 call write_iter_nl(out_dm_proj_basis)
2321 write(aux, '(a)') "# do ik = 1, nik "
2322 call write_iter_string(out_dm_proj_basis, aux)
2323 call write_iter_nl(out_dm_proj_basis)
2324 write(aux, '(a)') "# do ist = istart, iend"
2325 call write_iter_string(out_dm_proj_basis, aux)
2326 call write_iter_nl(out_dm_proj_basis)
2327 write(aux, '(a)') "# write E(ist, ik)"
2328 call write_iter_string(out_dm_proj_basis, aux)
2329 call write_iter_nl(out_dm_proj_basis)
2330
2331 write(aux, '(a)') "# do ik = 1, nik "
2332 call write_iter_string(out_dm_proj_basis, aux)
2333 call write_iter_nl(out_dm_proj_basis)
2334 write(aux, '(a)') "# do ist = istart, iend"
2335 call write_iter_string(out_dm_proj_basis, aux)
2336 call write_iter_nl(out_dm_proj_basis)
2337 write(aux, '(a)') "# write occ(ist, ik)"
2338 call write_iter_string(out_dm_proj_basis, aux)
2339 call write_iter_nl(out_dm_proj_basis)
2340
2341 write(aux, '(a)') "# do ik = 1, nik "
2342 call write_iter_string(out_dm_proj_basis, aux)
2343 call write_iter_nl(out_dm_proj_basis)
2344 write(aux, '(a)') "# write Re(rho_off_diagonal(:)), Im(rho_off_diagonal(:))"
2345 call write_iter_string(out_dm_proj_basis, aux)
2346 call write_iter_nl(out_dm_proj_basis)
2347 write(aux, '(a)') "# ! where 1D array rho_off_diagonal is packed as:"
2348 call write_iter_string(out_dm_proj_basis, aux)
2349 call write_iter_nl(out_dm_proj_basis)
2350 write(aux, '(a)') "# ! do jst = istart, iend ! column"
2351 call write_iter_string(out_dm_proj_basis, aux)
2352 call write_iter_nl(out_dm_proj_basis)
2353 write(aux, '(a)') "# ! do ist = istart, jst-1 ! row"
2354 call write_iter_string(out_dm_proj_basis, aux)
2355 call write_iter_nl(out_dm_proj_basis)
2356
2357 write(aux, '(a15)') "# w(ik) "
2358 call write_iter_string(out_dm_proj_basis, aux)
2359 call write_iter_double(out_dm_proj_basis, this%adiabatic_st%kweights(1:this%adiabatic_st%nik), this%adiabatic_st%nik)
2360 call write_iter_nl(out_dm_proj_basis)
2361
2362 call td_write_print_header_end(out_dm_proj_basis)
2363 end if
2364 else
2365
2366 ! gather rho_offd
2367 n_offd = ubound(this%rho_offd, dim = 1)
2368
2369 if (this%adiabatic_st%d%kpt%parallel) then
2370 if (this%adiabatic_st%d%kpt%mpi_grp%rank == 0) then
2371 safe_allocate(rho_offd(1:n_offd, this%adiabatic_st%nik))
2372 end if
2373 safe_allocate(recvcnts(1:this%adiabatic_st%d%kpt%mpi_grp%size))
2374 safe_allocate(rdispls(1:this%adiabatic_st%d%kpt%mpi_grp%size))
2376 incount = n_offd * this%adiabatic_st%d%kpt%nlocal()
2377 recvcnts(:) = n_offd * this%adiabatic_st%d%kpt%num(:)
2378
2379 call mpi_displacements(recvcnts, rdispls)
2380 call this%adiabatic_st%d%kpt%mpi_grp%gatherv(this%rho_offd(:, this%adiabatic_st%d%kpt%start:this%adiabatic_st%d%kpt%end), &
2381 incount, mpi_double_complex, rho_offd, recvcnts, rdispls, mpi_double_complex, 0)
2382
2383 safe_deallocate_a(recvcnts)
2384 safe_deallocate_a(rdispls)
2385 else
2386 safe_allocate_source(rho_offd(1:n_offd, this%adiabatic_st%nik), this%rho_offd)
2387 end if
2388
2389 ! output
2390 if (this%adiabatic_st%system_grp%is_root()) then
2391 call write_iter_string(out_dm_proj_basis, "# ------------")
2392 call write_iter_start(out_dm_proj_basis)
2393 call write_iter_double(out_dm_proj_basis, this%adiabatic_st%qtot, 1)
2394 call write_iter_nl(out_dm_proj_basis)
2395 do ik = 1, this%adiabatic_st%nik
2396 call write_iter_double(out_dm_proj_basis, this%adiabatic_st%eigenval(this%istart:this%iend, ik), this%iend-this%istart+1)
2397 call write_iter_nl(out_dm_proj_basis)
2398 end do
2399 do ik = 1, this%adiabatic_st%nik
2400 call write_iter_double(out_dm_proj_basis, this%adiabatic_st%occ(this%istart:this%iend, ik), this%iend-this%istart+1)
2401 call write_iter_nl(out_dm_proj_basis)
2402 end do
2403 do ik = 1, this%adiabatic_st%nik
2404 call write_iter_double(out_dm_proj_basis, real(rho_offd(1:n_offd, ik)), n_offd)
2405 call write_iter_double(out_dm_proj_basis, aimag(rho_offd(1:n_offd, ik)), n_offd)
2406 call write_iter_nl(out_dm_proj_basis)
2407 end do
2408 end if
2409
2410 safe_deallocate_a(rho_offd)
2411 end if
2412
2413 pop_sub(td_write_dm_proj_basis)
2414 end subroutine td_write_dm_proj_basis
2415
2416#ifdef HAVE_MPI
2417 subroutine slmpi_create_shared_memory_window(number_of_elements, intranode_grp, window, array)
2418 use iso_c_binding
2419 integer(int64), intent(in) :: number_of_elements
2420 type(mpi_grp_t), intent(in) :: intranode_grp
2421 type(mpi_win), intent(out) :: window
2422 real(real32), pointer, intent(out) :: array(:)
2423
2424 type(c_ptr) :: ptr
2425 integer(kind=MPI_ADDRESS_KIND) :: window_size
2426 integer :: disp_unit
2427
2428 assert(not_in_openmp())
2429
2430 ! allocate only on rank 0 of each node
2431 if (intranode_grp%rank == 0) then
2432 window_size = number_of_elements * 4_mpi_address_kind
2433 else
2434 window_size = 0_mpi_address_kind
2435 end if
2436 assert(number_of_elements * 4 < huge(0_mpi_address_kind))
2437 assert(window_size >= 0)
2438 disp_unit = 4
2439 call mpi_win_allocate_shared(window_size, disp_unit, mpi_info_null, &
2440 intranode_grp%comm, ptr, window)
2441 ! get pointer on all ranks
2442 if (intranode_grp%rank /= 0) then
2443 call mpi_win_shared_query(window, 0, window_size, disp_unit, ptr)
2444 end if
2445 ! get fortran pointer
2446 call c_f_pointer(ptr, array, [number_of_elements])
2447
2448 ! start access epoch
2449 call mpi_win_lock_all(mpi_mode_nocheck, window)
2450
2451 end subroutine slmpi_create_shared_memory_window
2452#endif
2453
2454end module dm_propagation_oct_m
int access(const char *__name, int __type) __attribute__((__nothrow__
--------------— gemm ---------------— performs one of the matrix-matrix operations
Definition: blas.F90:498
--------------— syrk, herk ---------------— performs one of the symmetric rank k operations
Definition: blas.F90:667
--------------— scal ---------------— Scales a vector by a constant.
Definition: blas.F90:162
constant times a vector plus a vector
Definition: lalg_basic.F90:192
scales a vector by a constant
Definition: lalg_basic.F90:168
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:180
Writes to the corresponding file and adds one to the iteration. Must be called after write_iter_init(...
Definition: write_iter.F90:161
double exp(double __x) __attribute__((__nothrow__
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
subroutine, public zbatch_axpy_function(np, aa, xx, psi, nst)
This routine performs a set of axpy operations for each function x of a batch (xx),...
Definition: batch_ops.F90:3543
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:118
This module implements a calculator for the density and defines related functions.
Definition: density.F90:120
subroutine, public density_calc(st, gr, density, istin, ep, vnl, phase)
Computes the density from the orbitals in st.
Definition: density.F90:811
subroutine lifetime(dmp, ik, ibnd, nik_skip, gam)
Calculate the total scattering rate (inverse lifetime) for a given state.
subroutine update_wfc_occ(ik, gr, istart, iend, nresd, ad_st, resd, occ, v_mat, st, pop)
Update states directly from diagonalization (no Procrustes).
subroutine iopar_close_trans_rate(system_grp, dmp)
Finalize transition rate resources.
subroutine lindblad_from_epw(dmp, hm, kpt, system_grp, namespace, nresd_k, dt, rho_mat_k)
Evolve the density matrix under EPW-derived Lindblad dissipation.
subroutine check_set_positive(locc, npos, ik, namespace, occ)
Checks and truncates small negative eigenvalues to zero.
subroutine calc_overlap_state(ik, gr, ad_st, st, istart_ad, iend_ad, istart_st, iend_st, overlap)
Calculate the overlap matrix between two states in the (istart, iend) active space.
subroutine lindblad_uniform(dmp, kpt, nresd_k, dt, rho_mat_k)
Evolve the density matrix in time under uniform dissipation.
subroutine construct_density_matrix(nresd, ik, st, istart, iend, overlap_ad_ks, overlap_resd_ks, rho_mat, rho_offd)
Construct the full density matrix in the adiabatic and residual basis.
subroutine, public dm_propagation_init_run(dmp, namespace, space, gr, ions, st, hm, mc, from_scratch)
Initialise the adiabatic states prior to running TD propagation.
integer function get_vector_field_index(dmp, hm, namespace)
Get the flattened 1D index of the current vector potential on the discrete EPW vector field grid.
real(real64) function get_trans_rate(dmp, nik_mp, jbnd, ibnd, k, kq, p_block)
Get transition rate from state (k, ibnd) to (kq, jbnd).
subroutine update_wfc_occ_procrustes(ik, gr, istart, iend, nresd, ad_st, resd, overlap_ad_ks, overlap_resd_ks, nrm2_tdks, occ_tilde, v_mat, st, pop)
Update states using Procrustes transformation to ensure time continuity.
subroutine lindblad_operator_epw(dmp, ik, nik_skip, nresd, rho_diag, den_mat, l_mat)
Calculate the Lindblad dissipator matrix using EPW electron-phonon scattering rates.
subroutine, public dm_end_run(system_grp, dmp)
logical function is_hermitian(n, mat)
Check if a matrix is Hermitian.
subroutine transition_rate_uniform(uniform, ad_st, istart, iend, ik, rtrans)
Calculate state transition rates assuming uniform electron-phonon coupling.
subroutine iopar_read_trans_rate(ia, system_grp, namespace, dmp)
Read in transition rates to the shared memory window and then broadcast via internode communicator.
subroutine broadcast_occupation(occ, kpt, parstate, istart, iend)
subroutine population_in_adiabatic(ik, ad_st, st, overlap, istart, iend, pop)
Calculate number of electrons in the adiabatic basis.
subroutine dmp_init(this, namespace, st, space, hm)
Initialise an instance of density matrix dissipation.
subroutine build_epw_kmap(namespace, kpoints, dmp)
Map internal k-point indices to the 1D EPW Monkhorst-Pack grid and verify mesh compatibility.
subroutine collision_from_epw(dmp, hm, kpt, system_grp, namespace, nresd_k, dt, rho_mat_k)
Evolve the density matrix subject to the electron-phonon collision integral.
subroutine construct_residuals(gr, namespace, ad_st, st, ik, othn, istart, iend, overlap_ad_ks, nrm2_tdks, nresd, overlap_resd_ks, resd)
Construct the residual basis and its overlap with TDKS wavefunctions.
subroutine total_population(ik, st, gr, nrm2, pop)
Calculate total population.
subroutine get_gamma(dmp, ik, ibnd, nik_skip, gam_in, gam_out)
Calculate in/out scattering rates (Gamma) for a specific state (ik, ibnd).
subroutine, public dm_propagation_run(dmp, namespace, space, gr, ions, st, mc, hm, ks, iter, dt, ext_partners, update_energy)
Density matrix propagation.
subroutine dm_propagation_update_trans_rate(this, hm, system_grp, namespace)
Read and update the EPW transition matrix only when the vector field index changes.
subroutine lindblad_2times(dmp, kpt, nresd_k, dt, rho_mat_k)
Evolve the density matrix using the phenomenological two-time (T1/T2) relaxation model.
subroutine lindblad_operator_uniform(nresd, istart, iend, rtrans, den_mat, l_mat)
Calculate the Lindblad dissipator matrix for uniform decay.
subroutine iopar_open_trans_rate(namespace, ions, hm, system_grp, dmp)
Read in metadata of transition rates, build intra/inter communicators and shared memory window.
subroutine td_write_dm_proj_basis(this, out_dm_proj_basis, iter)
Write density matrix information to file.
subroutine dissipation(hm, st, namespace, nresd_k, dt, dmp, rho_mat_k)
Evolve the density matrix in time under dissipation.
subroutine calc_overlap_single(ik, gr, st, psi, istart, iend, overlap, reduce)
Calculates the dot products between a vector of mesh functions and a state within the (istart,...
subroutine update_st(dmp, ik, gr, namespace, nresd, overlap_ad_ks, overlap_resd_ks, nrm2_tdks, resd, st, rho_mat, pop)
Diagonalize the density matrix to update occupations and wavefunctions.
subroutine, public eigensolver_init(eigens, namespace, gr, st, hm, mc, space, deactivate_oracle)
subroutine, public eigensolver_end(eigens)
integer, parameter, public spin_polarized
real(real64), parameter, public m_two
Definition: global.F90:200
real(real64), parameter, public m_zero
Definition: global.F90:198
real(real64), parameter, public p_ry
Definition: global.F90:237
logical pure function, public not_in_openmp()
Definition: global.F90:565
complex(real64), parameter, public m_z0
Definition: global.F90:208
real(real64), parameter, public m_epsilon
Definition: global.F90:214
complex(real64), parameter, public m_z1
Definition: global.F90:209
real(real64), parameter, public m_half
Definition: global.F90:204
real(real64), parameter, public m_one
Definition: global.F90:199
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module defines classes and functions for interaction partners.
integer, parameter, public kpoints_monkh_pack
Definition: kpoints.F90:224
subroutine, public kpoints_to_reduced(latt, kin, kout)
Definition: kpoints.F90:1158
This module defines functions over batches of mesh functions.
Definition: mesh_batch.F90:116
subroutine, public mesh_batch_nrm2(mesh, aa, nrm2, reduce)
Calculate the norms (norm2, not the square!) of a batch of mesh functions.
Definition: mesh_batch.F90:179
subroutine, public zmesh_batch_dotp_matrix(mesh, aa, bb, dot, reduce)
Calculate the overlap matrix of two batches.
subroutine, public zmesh_batch_mf_dotp(mesh, aa, psi, dot, reduce, nst)
calculate the dot products between a batch and a vector of mesh functions
This module defines various routines, operating on mesh functions.
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1066
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:523
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:408
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:689
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:592
This module contains some common usage patterns of MPI routines.
Definition: mpi_lib.F90:115
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:621
/* To use the profiling module, call profiling_in and profiling_out with the label of the region as a...
Definition: profiling.F90:143
integer, parameter, public restart_dm
Definition: restart.F90:154
integer, parameter, public restart_gs
Definition: restart.F90:154
integer, parameter, public restart_type_dump
Definition: restart.F90:182
integer, parameter, public restart_type_load
Definition: restart.F90:182
subroutine, public zstates_elec_orthogonalize_single_batch(st, mesh, nst, iqn, phi, normalize, mask, overlap, norm, Theta_fi, beta_ij, against_all)
orthogonalize a single wave function against a set of states
integer pure function, public states_elec_block_max(st, ib)
return index of last state in block ib
subroutine, public states_elec_end(st)
finalize the states_elec_t object
subroutine, public states_elec_copy(stout, stin, exclude_wfns, exclude_eigenval, special, dest_type, copy_data)
make a (selective) copy of a states_elec_t object
integer pure function, public states_elec_block_min(st, ib)
return index of first state in block ib
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 td_write_print_header_init(out)
subroutine, public td_write_print_header_end(out)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
type(unit_t), public unit_kelvin
For converting energies into temperatures.
type(unit_system_t), public units_inp
the units systems for reading and writing
subroutine, public v_ks_calc(ks, namespace, space, hm, st, ions, ext_partners, calc_eigenval, time, calc_energy, calc_current, force_semilocal)
Definition: v_ks.F90:786
Explicit interfaces to C functions, defined in write_iter_low.cc.
Definition: write_iter.F90:114
subroutine, public write_iter_string(out, string)
Definition: write_iter.F90:263
Distribution of N instances over mpi_grpsize processes, for the local rank mpi_grprank....
Extension of space that contains the knowledge of the spin dimension.
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:169
This is defined even when running serial.
Definition: mpi.F90:142
Stores all communicators and groups.
Definition: multicomm.F90:206
The states_elec_t class contains all electronic wave functions.
int true(void)