34 use,
intrinsic :: iso_fortran_env
62 integer,
public,
parameter :: &
69 integer,
public :: exp_method
70 real(real64) :: lanczos_tol
71 real(real64) :: chebyshev_tol
72 integer,
public :: exp_order
74 logical,
public :: full_batch = .false.
85 type(exponential_t),
intent(out) :: te
86 type(namespace_t),
intent(in) :: namespace
87 logical,
optional,
intent(in) :: full_batch
146 select case (te%exp_method)
159 call parse_variable(namespace,
'TDChebyshevTol', 1e-10_real64, te%chebyshev_tol)
173 call parse_variable(namespace,
'TDLanczosTol', 1e-6_real64, te%lanczos_tol)
190 call parse_variable(namespace,
'TDExpOrder', default__tdexporder, te%exp_order)
194 message(1) =
"TDExpOrder is only relevant for TDExponentialMethod = taylor"
199 te%arnoldi_gs = option__arnoldiorthogonalization__cgs
200 if (te%exp_method == exp_lanczos)
then
215 call parse_variable(namespace,
'ArnoldiOrthogonalization', option__arnoldiorthogonalization__cgs, &
232 teo%exp_method = tei%exp_method
233 teo%lanczos_tol = tei%lanczos_tol
234 teo%exp_order = tei%exp_order
235 teo%arnoldi_gs = tei%arnoldi_gs
245 class(
mesh_t),
intent(in) :: mesh
247 integer,
intent(in) :: ist
248 integer,
intent(in) :: ik
249 complex(real64),
contiguous,
intent(inout) :: zpsi(:, :)
250 real(real64),
intent(in) :: deltat
251 real(real64),
optional,
intent(in) :: vmagnus(mesh%np, hm%d%nspin, 2)
252 logical,
optional,
intent(in) :: imag_time
255 complex(real64),
allocatable :: zpsi_inh(:, :)
261 if (hm%phase%is_allocated())
then
262 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .false.)
268 safe_allocate(zpsi_inh(1:mesh%np_part, 1:hm%d%dim))
270 call wfs_elec_init(inh_psib, hm%d%dim, ist, ist, zpsi_inh, ik)
271 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
272 vmagnus=vmagnus, imag_time=imag_time, inh_psib=inh_psib)
274 safe_deallocate_a(zpsi_inh)
276 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
277 vmagnus=vmagnus, imag_time=imag_time)
282 if (hm%phase%is_allocated())
then
283 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .
true.)
307 subroutine exponential_apply_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, vmagnus, imag_time, inh_psib)
310 class(
mesh_t),
intent(in) :: mesh
312 class(
batch_t),
intent(inout) :: psib
313 real(real64),
intent(in) :: deltat
314 class(
batch_t),
optional,
intent(inout) :: psib2
315 real(real64),
optional,
intent(in) :: deltat2
316 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
317 logical,
optional,
intent(in) :: imag_time
318 class(
batch_t),
optional,
intent(inout) :: inh_psib
320 complex(real64) :: deltat_, deltat2_
322 logical :: imag_time_
329 assert(
present(psib2) .eqv.
present(deltat2))
330 if (
present(inh_psib))
then
331 assert(inh_psib%nst == psib%nst)
334 if (
present(vmagnus))
then
337 assert(
size(vmagnus, 1) >= mesh%np)
338 assert(
size(vmagnus, 2) == hm%d%nspin)
339 assert(
size(vmagnus, 3) == 2)
341 write(
message(1),
'(a)')
'Magnus operators only implemented for electrons at the moment'
350 deltat_ = -
m_zi*deltat
351 if (
present(deltat2)) deltat2_ =
m_zi*deltat2
353 deltat_ = cmplx(deltat,
m_zero, real64)
354 if (
present(deltat2)) deltat2_ = cmplx(deltat2,
m_zero, real64)
357 if (.not. hm%is_hermitian() .and. te%exp_method ==
exp_chebyshev)
then
358 write(
message(1),
'(a)')
'The Chebyshev expansion cannot be used for non-Hermitian operators.'
359 write(
message(2),
'(a)')
'Please use the Lanczos exponentiation scheme ("TDExponentialMethod = lanczos")'
360 write(
message(3),
'(a)')
'or the Taylor expansion ("TDExponentialMethod = taylor") method.'
364 select case (te%exp_method)
367 if (
present(deltat2))
then
369 psib2, deltat2_, vmagnus)
374 if (
present(inh_psib))
then
375 if (
present(deltat2))
then
377 psib2, deltat2_, vmagnus, inh_psib)
380 vmagnus=vmagnus, inh_psib=inh_psib)
385 if (
present(psib2))
call psib%copy_data_to(mesh%np, psib2)
387 if (
present(inh_psib))
then
390 if (
present(psib2))
then
392 if (
present(inh_psib))
then
398 if (
present(inh_psib))
then
399 write(
message(1),
'(a)')
'Chebyshev exponential ("TDExponentialMethod = chebyshev")'
400 write(
message(2),
'(a)')
'with inhomogeneous term is not implemented'
407 chebyshev_function =>
chebyshev_exp_t(hm%spectral_half_span, hm%spectral_middle_point, deltat)
409 if (
present(psib2))
call psib%copy_data_to(mesh%np, psib2)
411 if (
present(psib2))
then
414 deallocate(chebyshev_function)
423 subroutine exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, vmagnus, inh_psib, phik_shift)
426 class(
mesh_t),
intent(in) :: mesh
428 class(
batch_t),
intent(inout) :: psib
429 complex(real64),
intent(in) :: deltat
430 class(
batch_t),
optional,
intent(inout) :: psib2
431 complex(real64),
optional,
intent(in) :: deltat2
432 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
433 class(
batch_t),
optional,
intent(inout) :: inh_psib
434 integer,
optional,
intent(in) :: phik_shift
436 complex(real64) :: zfact, zfact2
437 integer :: iter, denom, phik_shift_
438 logical :: zfact_is_real
439 class(
batch_t),
allocatable :: psi1b, hpsi1b
444 call psib%clone_to(psi1b)
445 call psib%clone_to(hpsi1b)
449 zfact_is_real = abs(deltat-real(deltat)) <
m_epsilon
451 if (
present(psib2))
call psib%copy_data_to(mesh%np, psib2)
453 if (
present(inh_psib))
then
455 call batch_axpy(mesh%np, real(zfact), inh_psib, psib)
457 if (
present(psib2))
then
458 zfact2 = zfact2*deltat2
459 call batch_axpy(mesh%np, real(zfact2), inh_psib, psib2)
466 do iter = 1, te%exp_order
467 denom = iter+phik_shift_
468 if (
present(inh_psib)) denom = denom + 1
469 zfact = zfact*(-
m_zi*deltat)/denom
470 if (
present(deltat2)) zfact2 = zfact2*(-
m_zi*deltat2)/denom
471 zfact_is_real = .not. zfact_is_real
478 call operate_batch(hm, namespace, mesh, psi1b, hpsi1b, vmagnus)
480 if (
present(inh_psib))
then
481 call operate_batch(hm, namespace, mesh, inh_psib, hpsi1b, vmagnus)
483 call operate_batch(hm, namespace, mesh, psib, hpsi1b, vmagnus)
487 if (zfact_is_real)
then
488 call batch_axpy(mesh%np, real(zfact), hpsi1b, psib)
489 if (
present(psib2))
call batch_axpy(mesh%np, real(zfact2), hpsi1b, psib2)
492 if (
present(psib2))
call batch_axpy(mesh%np, zfact2, hpsi1b, psib2)
495 if (iter /= te%exp_order)
call hpsi1b%copy_data_to(mesh%np, psi1b)
501 safe_deallocate_a(psi1b)
502 safe_deallocate_a(hpsi1b)
511 class(
mesh_t),
intent(in) :: mesh
513 class(
batch_t),
intent(inout) :: psib
514 complex(real64),
intent(in) :: deltat
515 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
516 class(
batch_t),
optional,
intent(in) :: inh_psib
518 class(
batch_t),
allocatable :: tmpb
522 if (
present(inh_psib))
then
523 call inh_psib%clone_to(tmpb, copy_data=.
true.)
526 call batch_axpy(mesh%np, real(deltat, real64), tmpb, psib)
550 class(
mesh_t),
intent(in) :: mesh
552 class(
batch_t),
intent(inout) :: psib
553 complex(real64),
intent(in) :: deltat
555 complex(real64) function fun(z)
557 complex(real64),
intent(in) :: z
560 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
562 integer :: iter, l, ii, ist, max_initialized
563 complex(real64),
allocatable :: hamilt(:,:,:), expo(:,:,:)
564 real(real64),
allocatable :: beta(:), res(:), norm(:)
565 integer,
parameter :: max_order = 200
571 if (te%exp_method /= exp_lanczos)
then
572 message(1) =
"The exponential method needs to be set to Lanzcos (TDExponentialMethod=lanczos)."
576 safe_allocate(beta(1:psib%nst))
577 safe_allocate(res(1:psib%nst))
578 safe_allocate(norm(1:psib%nst))
579 safe_allocate(vb(1:max_order))
580 call psib%clone_to(vb(1)%p)
583 call psib%copy_data_to(mesh%np, vb(1)%p, async=.
true.)
586 if (te%full_batch) beta = norm2(beta)
589 if (all(abs(beta) <= 1.0e-12_real64))
then
590 safe_deallocate_a(beta)
591 safe_deallocate_a(res)
592 safe_deallocate_a(norm)
594 safe_deallocate_a(vb)
602 safe_allocate(hamilt(1:max_order+1, 1:max_order+1, 1:psib%nst))
603 safe_allocate( expo(1:max_order+1, 1:max_order+1, 1:psib%nst))
606 do iter = 1, max_order
607 call psib%clone_to(vb(iter + 1)%p)
608 max_initialized = iter + 1
611 call operate_batch(hm, namespace, mesh, vb(iter)%p, vb(iter+1)%p, vmagnus)
614 if (hm%is_hermitian())
then
616 hamilt(1:max(l-1, 1), iter, 1:psib%nst) =
m_zero
620 hamilt(iter, 1:iter-2, 1:psib%nst) =
m_zero
626 normalize = .false., overlap = hamilt(l:iter, iter, 1:psib%nst), norm = hamilt(iter + 1, iter, 1:psib%nst), &
627 gs_scheme = te%arnoldi_gs, full_batch = te%full_batch)
637 hm%is_hermitian(), tridiagonal=hm%is_hermitian())
638 res(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo(iter, 1, ii)))
642 if (all(abs(hamilt(iter + 1, iter, :)) < 1.0e4_real64*
m_epsilon))
exit
647 if (abs(hamilt(iter + 1, iter, ist)) >= 1.0e4_real64 *
m_epsilon)
then
648 norm(ist) =
m_one / abs(hamilt(iter + 1, iter, ist))
652 call batch_scal(mesh%np, norm, vb(iter+1)%p, a_full = .false.)
654 if (iter > 3 .and. all(res < te%lanczos_tol))
exit
658 if (iter == max_order)
then
659 write(
message(1),
'(a,i5,a,es9.2)')
'Lanczos exponential expansion did not converge after ', iter, &
660 ' iterations. Residual: ', maxval(res)
663 write(
message(1),
'(a,i5)')
'Debug: Lanczos exponential iterations: ', iter
669 call batch_scal(mesh%np, expo(1,1,1:psib%nst), psib, a_full = .false.)
672 call batch_axpy(mesh%np, beta(1:psib%nst)*expo(ii,1,1:psib%nst), vb(ii)%p, psib, a_full = .false.)
677 do ii = 1, max_initialized
681 safe_deallocate_a(vb)
682 safe_deallocate_a(hamilt)
683 safe_deallocate_a(expo)
684 safe_deallocate_a(beta)
685 safe_deallocate_a(res)
686 safe_deallocate_a(norm)
711 class(
mesh_t),
intent(in) :: mesh
713 class(
batch_t),
intent(inout) :: psib
714 real(real64),
intent(in) :: deltat
716 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
718 integer :: j, order_needed
719 complex(real64) :: coefficient
720 complex(real64),
allocatable :: coefficients(:)
721 real(real64) :: error
722 class(
batch_t),
allocatable,
target :: psi0, psi1, psi2
723 class(
batch_t),
pointer :: psi_n, psi_n1, psi_n2
724 integer,
parameter :: max_order = 200
729 call psib%clone_to(psi0)
730 call psib%clone_to(psi1)
731 call psib%clone_to(psi2)
732 call psib%copy_data_to(mesh%np, psi0)
734 order_needed = max_order
736 error = chebyshev_function%get_error(j)
737 if (error >
m_zero .and. error < te%chebyshev_tol)
then
743 call chebyshev_function%get_coefficients(j, coefficients)
746 call batch_scal(mesh%np, coefficients(0), psib)
750 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi0, psi1)
753 call batch_axpy(mesh%np, coefficients(1), psi1, psib)
760 do j = 2, order_needed
762 call operate_batch(hm, namespace, mesh, psi_n1, psi_n, vmagnus)
763 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi_n1, psi_n)
768 call batch_axpy(mesh%np, coefficients(j), psi_n, psib)
771 if (mod(j, 3) == 2)
then
775 else if (mod(j, 3) == 1)
then
786 if (order_needed == max_order)
then
787 write(
message(1),
'(a,i5,a,es9.2)')
'Chebyshev exponential expansion did not converge after ', j, &
788 ' iterations. Coefficient: ', coefficient
791 write(
message(1),
'(a,i5)')
'Debug: Chebyshev exponential iterations: ', j
798 safe_deallocate_a(psi0)
799 safe_deallocate_a(psi1)
800 safe_deallocate_a(psi2)
802 safe_deallocate_a(coefficients)
810 subroutine operate_batch(hm, namespace, mesh, psib, hpsib, vmagnus)
813 class(
mesh_t),
intent(in) :: mesh
814 class(
batch_t),
intent(inout) :: psib
815 class(
batch_t),
intent(inout) :: hpsib
816 real(real64),
optional,
intent(in) :: vmagnus(:, :, :)
820 if (
present(vmagnus))
then
821 call hm%zmagnus_apply(namespace, mesh, psib, hpsib, vmagnus)
823 call hm%zapply(namespace, mesh, psib, hpsib)
836 type(
grid_t),
intent(inout) :: gr
839 real(real64),
intent(in) :: deltat
840 integer,
optional,
intent(inout) :: order
843 real(real64) :: zfact
855 do i = 1, te%exp_order
856 zfact = zfact * deltat / i
864 do ik = st%d%kpt%start, st%d%kpt%end
865 do ib = st%group%block_start, st%group%block_end
867 call batch_axpy(gr%np, -
m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik))
868 call batch_axpy(gr%np, zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
886 do ik = st%d%kpt%start, st%d%kpt%end
887 do ib = st%group%block_start, st%group%block_end
888 call batch_axpy(gr%np, deltat, st1%group%psib(ib, ik), st%group%psib(ib, ik))
893 do i = 1, te%exp_order
894 zfact = zfact * deltat / (i+1)
902 do ik = st%d%kpt%start, st%d%kpt%end
903 do ib = st%group%block_start, st%group%block_end
905 call batch_axpy(gr%np, -
m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik))
906 call batch_axpy(gr%np, deltat * zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
917 if (
present(order)) order = te%exp_order*st%nik*st%nst
925 class(
mesh_t),
intent(in) :: mesh
927 class(
batch_t),
intent(inout) :: psib
928 real(real64),
intent(in) :: deltat
929 integer,
intent(in) :: k
930 real(real64),
optional,
intent(in) :: vmagnus(:,:,:)
933 complex(real64) :: deltat_
938 if (
present(vmagnus))
then
941 assert(
size(vmagnus, 1) >= mesh%np)
942 assert(
size(vmagnus, 2) == hm%d%nspin)
943 assert(
size(vmagnus, 3) == 2)
945 write(
message(1),
'(a)')
'Magnus operators only implemented for electrons at the moment'
950 if (.not. hm%is_hermitian() .and. te%exp_method ==
exp_chebyshev)
then
951 write(
message(1),
'(a)')
'The Chebyshev expansion for the exponential will only converge if the imaginary'
952 write(
message(2),
'(a)')
'eigenvalues are small enough compared to the span of the real eigenvalues,'
953 write(
message(3),
'(a)')
'i.e., for ratios smaller than about 1e-3.'
954 write(
message(4),
'(a)')
'The Lanczos method ("TDExponentialMethod = lanczos") is guaranteed to'
955 write(
message(5),
'(a)')
'always converge in this case.'
959 deltat_ = cmplx(deltat,
m_zero, real64)
961 select case (te%exp_method)
968 else if (k == 2)
then
971 write(
message(1),
'(a)')
'Lanczos expansion not implemented for phi_k, k > 2'
978 else if (k == 2)
then
981 write(
message(1),
'(a)')
'Chebyshev expansion not implemented for phi_k, k > 2'
985 deallocate(chebyshev_function)
batchified version of the BLAS axpy routine:
scale a batch by a constant or vector
subroutine, public accel_finish()
This module implements batches of mesh functions.
This module implements common operations on batches of mesh functions.
subroutine, public batch_set_zero(this, np, async)
fill all mesh functions of the batch with zero
This module contains interfaces for BLAS routines You should not use these routines directly....
subroutine, public exponential_copy(teo, tei)
subroutine, public exponential_apply_all(te, namespace, gr, hm, st, deltat, order)
Note that this routine not only computes the exponential, but also an extra term if there is a inhomo...
subroutine operate_batch(hm, namespace, mesh, psib, hpsib, vmagnus)
subroutine exponential_apply_phi_batch(te, namespace, mesh, hm, psib, deltat, k, vmagnus)
subroutine, public exponential_init(te, namespace, full_batch)
integer, parameter, public exp_taylor
subroutine exponential_lanczos_batch(te, namespace, mesh, hm, psib, deltat, vmagnus, inh_psib)
subroutine exponential_apply_single(te, namespace, mesh, hm, zpsi, ist, ik, deltat, vmagnus, imag_time)
Wrapper to batchified routine for applying exponential to an array.
subroutine exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, vmagnus, inh_psib, phik_shift)
subroutine exponential_apply_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, vmagnus, imag_time, inh_psib)
This routine performs the operation:
subroutine, public exponential_lanczos_function_batch(te, namespace, mesh, hm, psib, deltat, fun, vmagnus)
Compute fun(H) psib, i.e. the application of a function of the Hamiltonian to a batch.
integer, parameter, public exp_chebyshev
subroutine exponential_cheby_batch(te, namespace, mesh, hm, psib, deltat, chebyshev_function, vmagnus)
Calculates the exponential of the Hamiltonian through an expansion in Chebyshev polynomials.
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
complex(real64), parameter, public m_zi
real(real64), parameter, public m_epsilon
complex(real64), parameter, public m_z1
real(real64), parameter, public m_one
This module implements the underlying real-space grid.
This module defines an abstract class for Hamiltonians.
subroutine, public zhamiltonian_elec_apply_all(hm, namespace, gr, st, hst)
pure logical function, public hamiltonian_elec_inh_term(hm)
subroutine, public zlalg_matrix_function(n, factor, a, fun_a, fun, hermitian, tridiagonal)
This routine calculates a function of a matrix by using an eigenvalue decomposition.
This module is intended to contain "only mathematical" functions and procedures.
complex(real64) pure function, public phi2(z)
Compute phi2(z) = (phi1(z)-1)/z = (exp(z) - z - 1)/z^2.
complex(real64) pure function, public exponential(z)
Wrapper for exponential.
complex(real64) pure function, public phi1(z)
Compute phi1(z) = (exp(z)-1)/z.
This module defines functions over batches of mesh functions.
subroutine, public mesh_batch_nrm2(mesh, aa, nrm2, reduce)
Calculate the norms (norm2, not the square!) of a batch of mesh functions.
subroutine, public zmesh_batch_orthogonalization(mesh, nst, psib, phib, normalize, overlap, norm, gs_scheme, full_batch)
Orthonormalizes states of phib to the orbitals of nst batches of psi.
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
subroutine, public messages_warning(no_lines, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_input_error(namespace, var, details, row, column)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
logical function, public parse_is_defined(namespace, name)
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
subroutine, public states_elec_end(st)
finalize the states_elec_t object
subroutine, public states_elec_copy(stout, stin, exclude_wfns, exclude_eigenval, special)
make a (selective) copy of a states_elec_t object
type(type_t), public type_cmplx
Class defining batches of mesh functions.
Description of the grid, containing information on derivatives, stencil, and symmetries.
The abstract Hamiltonian class defines a skeleton for specific implementations.
Describes mesh distribution to nodes.
The states_elec_t class contains all electronic wave functions.
batches of electronic states