34 use,
intrinsic :: iso_fortran_env
64 integer,
public,
parameter :: &
71 integer,
public :: exp_method
72 real(real64) :: lanczos_tol
73 real(real64) :: chebyshev_tol
74 integer,
public :: exp_order
76 logical,
public :: full_batch = .false.
85 type(namespace_t),
pointer :: namespace
86 class(mesh_t),
pointer :: mesh
88 procedure(operator_apply),
deferred :: apply
95 class(operator_t),
intent(in) :: this
96 class(batch_t),
intent(inout) :: psib
97 class(batch_t),
intent(inout) :: hpsib
103 class(hamiltonian_abst_t),
pointer :: hm
110 procedure hamiltonian_operator_constructor
117 type(exponential_t),
intent(out) :: te
118 type(namespace_t),
intent(in) :: namespace
119 logical,
optional,
intent(in) :: full_batch
178 select case (te%exp_method)
191 call parse_variable(namespace,
'TDChebyshevTol', 1e-10_real64, te%chebyshev_tol)
205 call parse_variable(namespace,
'TDLanczosTol', 1e-6_real64, te%lanczos_tol)
222 call parse_variable(namespace,
'TDExpOrder', default__tdexporder, te%exp_order)
226 message(1) =
"TDExpOrder is only relevant for TDExponentialMethod = taylor"
231 te%arnoldi_gs = option__arnoldiorthogonalization__cgs
232 if (te%exp_method == exp_lanczos)
then
247 call parse_variable(namespace,
'ArnoldiOrthogonalization', option__arnoldiorthogonalization__cgs, &
264 teo%exp_method = tei%exp_method
265 teo%lanczos_tol = tei%lanczos_tol
266 teo%exp_order = tei%exp_order
267 teo%arnoldi_gs = tei%arnoldi_gs
277 class(
mesh_t),
intent(in) :: mesh
279 integer,
intent(in) :: ist
280 integer,
intent(in) :: ik
281 complex(real64),
contiguous,
intent(inout) :: zpsi(:, :)
282 real(real64),
intent(in) :: deltat
283 logical,
optional,
intent(in) :: imag_time
286 complex(real64),
allocatable :: zpsi_inh(:, :)
292 if (hm%phase%is_allocated())
then
293 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .false.)
299 safe_allocate(zpsi_inh(1:mesh%np_part, 1:hm%d%dim))
301 call wfs_elec_init(inh_psib, hm%d%dim, ist, ist, zpsi_inh, ik)
302 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
303 imag_time=imag_time, inh_psib=inh_psib)
305 safe_deallocate_a(zpsi_inh)
307 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
313 if (hm%phase%is_allocated())
then
314 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .
true.)
338 subroutine exponential_apply_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, imag_time, inh_psib, op)
341 class(
mesh_t),
intent(in) :: mesh
343 class(
batch_t),
intent(inout) :: psib
344 real(real64),
intent(in) :: deltat
345 class(
batch_t),
optional,
intent(inout) :: psib2
346 real(real64),
optional,
intent(in) :: deltat2
347 logical,
optional,
intent(in) :: imag_time
348 class(
batch_t),
optional,
intent(inout) :: inh_psib
349 class(
operator_t),
target,
optional,
intent(in) :: op
351 complex(real64) :: deltat_, deltat2_
353 logical :: imag_time_
361 assert(
present(psib2) .eqv.
present(deltat2))
362 if (
present(inh_psib))
then
363 assert(inh_psib%nst == psib%nst)
366 if (
present(op))
then
376 deltat_ = -
m_zi*deltat
377 if (
present(deltat2)) deltat2_ =
m_zi*deltat2
379 deltat_ = cmplx(deltat,
m_zero, real64)
380 if (
present(deltat2)) deltat2_ = cmplx(deltat2,
m_zero, real64)
383 if (.not. hm%is_hermitian() .and. te%exp_method ==
exp_chebyshev)
then
384 write(
message(1),
'(a)')
'The Chebyshev expansion cannot be used for non-Hermitian operators.'
385 write(
message(2),
'(a)')
'Please use the Lanczos exponentiation scheme ("TDExponentialMethod = lanczos")'
386 write(
message(3),
'(a)')
'or the Taylor expansion ("TDExponentialMethod = taylor") method.'
390 select case (te%exp_method)
393 if (
present(deltat2))
then
399 if (
present(inh_psib))
then
400 if (
present(deltat2))
then
402 psib2, deltat2_, inh_psib)
410 if (
present(psib2))
then
413 call psib%copy_data_to(mesh%np, psib2)
415 psib2=psib2, deltat2=deltat2_)
416 if (
present(inh_psib))
then
418 psib2=psib2, deltat2=deltat2_)
422 if (
present(inh_psib))
then
428 if (
present(inh_psib))
then
429 write(
message(1),
'(a)')
'Chebyshev exponential ("TDExponentialMethod = chebyshev")'
430 write(
message(2),
'(a)')
'with inhomogeneous term is not implemented'
436 if (
present(psib2))
then
440 chebyshev_function =>
chebyshev_exp_t(hm%spectral_half_span, hm%spectral_middle_point, deltat)
441 if (
present(psib2))
then
442 chebyshev_function_dt2 =>
chebyshev_exp_t(hm%spectral_half_span, hm%spectral_middle_point, deltat2)
445 if (
present(psib2))
call psib%copy_data_to(mesh%np, psib2)
447 deallocate(chebyshev_function)
448 if (
present(psib2))
then
450 deallocate(chebyshev_function_dt2)
455 if (.not.
present(op))
then
456 safe_deallocate_p(op_)
464 subroutine exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat, op, psib2, deltat2, inh_psib, phik_shift)
467 class(
mesh_t),
intent(in) :: mesh
469 class(
batch_t),
intent(inout) :: psib
470 complex(real64),
intent(in) :: deltat
472 class(
batch_t),
optional,
intent(inout) :: psib2
473 complex(real64),
optional,
intent(in) :: deltat2
474 class(
batch_t),
optional,
intent(inout) :: inh_psib
475 integer,
optional,
intent(in) :: phik_shift
477 complex(real64) :: zfact, zfact2
478 integer :: iter, denom, phik_shift_
479 logical :: zfact_is_real
480 class(
batch_t),
allocatable :: psi1b, hpsi1b
485 call psib%clone_to(psi1b)
486 call psib%clone_to(hpsi1b)
490 zfact_is_real = abs(deltat-real(deltat, real64)) <
m_epsilon
492 if (
present(psib2))
call psib%copy_data_to(mesh%np, psib2)
494 if (
present(inh_psib))
then
496 call batch_axpy(mesh%np, real(zfact, real64), inh_psib, psib)
498 if (
present(psib2))
then
499 zfact2 = zfact2*deltat2
500 call batch_axpy(mesh%np, real(zfact2, real64), inh_psib, psib2)
507 do iter = 1, te%exp_order
508 denom = iter+phik_shift_
509 if (
present(inh_psib)) denom = denom + 1
510 zfact = zfact*(-
m_zi*deltat)/denom
511 if (
present(deltat2)) zfact2 = zfact2*(-
m_zi*deltat2)/denom
512 zfact_is_real = .not. zfact_is_real
519 call op%apply(psi1b, hpsi1b)
521 if (
present(inh_psib))
then
522 call op%apply(inh_psib, hpsi1b)
524 call op%apply(psib, hpsi1b)
528 if (zfact_is_real)
then
529 call batch_axpy(mesh%np, real(zfact, real64), hpsi1b, psib)
530 if (
present(psib2))
call batch_axpy(mesh%np, real(zfact2, real64), hpsi1b, psib2)
533 if (
present(psib2))
call batch_axpy(mesh%np, zfact2, hpsi1b, psib2)
536 if (iter /= te%exp_order)
call hpsi1b%copy_data_to(mesh%np, psi1b)
542 safe_deallocate_a(psi1b)
543 safe_deallocate_a(hpsi1b)
555 class(
mesh_t),
intent(in) :: mesh
557 class(
batch_t),
intent(inout) :: psib
558 complex(real64),
intent(in) :: deltat
560 class(
batch_t),
optional,
intent(in) :: inh_psib
561 class(
batch_t),
optional,
intent(inout) :: psib2
562 complex(real64),
optional,
intent(in) :: deltat2
564 class(
batch_t),
allocatable :: tmpb, tmpb2
568 assert(
present(psib2) .eqv.
present(deltat2))
570 if (
present(inh_psib))
then
571 call inh_psib%clone_to(tmpb, copy_data=.
true.)
572 if (
present(psib2))
then
575 call inh_psib%clone_to(tmpb2, copy_data=.
true.)
577 psib2=tmpb2, deltat2=deltat2)
578 call batch_axpy(mesh%np, real(deltat, real64), tmpb, psib)
579 call batch_axpy(mesh%np, real(deltat2, real64), tmpb2, psib2)
581 safe_deallocate_a(tmpb2)
585 call batch_axpy(mesh%np, real(deltat, real64), tmpb, psib)
588 safe_deallocate_a(tmpb)
590 if (
present(psib2))
then
592 psib2=psib2, deltat2=deltat2)
618 class(
mesh_t),
intent(in) :: mesh
620 class(
batch_t),
intent(inout) :: psib
621 complex(real64),
intent(in) :: deltat
623 complex(real64) function fun(z)
625 complex(real64),
intent(in) :: z
629 class(
batch_t),
optional,
intent(inout) :: psib2
630 complex(real64),
optional,
intent(in) :: deltat2
632 integer :: iter, l, ii, ist, max_initialized
633 complex(real64),
allocatable :: hamilt(:,:,:), expo(:,:,:), expo2(:,:,:)
634 real(real64),
allocatable :: beta(:), res(:), res2(:), norm(:)
635 integer,
parameter :: max_order = 200
637 logical :: have_dt2, converged
642 if (te%exp_method /= exp_lanczos)
then
643 message(1) =
"The exponential method needs to be set to Lanzcos (TDExponentialMethod=lanczos)."
651 have_dt2 =
present(psib2)
652 assert(
present(psib2) .eqv.
present(deltat2))
654 assert(psib2%nst == psib%nst)
657 safe_allocate(beta(1:psib%nst))
658 safe_allocate(res(1:psib%nst))
659 safe_allocate(norm(1:psib%nst))
660 safe_allocate(vb(1:max_order))
661 call psib%clone_to(vb(1)%p)
664 call psib%copy_data_to(mesh%np, vb(1)%p, async=.
true.)
667 if (te%full_batch) beta = norm2(beta)
670 if (all(abs(beta) <= 1.0e-12_real64))
then
671 safe_deallocate_a(beta)
672 safe_deallocate_a(res)
673 safe_deallocate_a(norm)
675 safe_deallocate_a(vb)
683 safe_allocate(hamilt(1:max_order+1, 1:max_order+1, 1:psib%nst))
684 safe_allocate( expo(1:max_order+1, 1:max_order+1, 1:psib%nst))
686 safe_allocate(expo2(1:max_order+1, 1:max_order+1, 1:psib%nst))
687 safe_allocate(res2(1:psib%nst))
691 do iter = 1, max_order-1
692 call psib%clone_to(vb(iter + 1)%p)
693 max_initialized = iter + 1
696 call op%apply(vb(iter)%p, vb(iter+1)%p)
699 if (hm%is_hermitian())
then
701 hamilt(1:max(l-1, 1), iter, 1:psib%nst) =
m_zero
705 hamilt(iter, 1:iter-2, 1:psib%nst) =
m_zero
711 normalize = .false., overlap = hamilt(l:iter, iter, 1:psib%nst), norm = hamilt(iter + 1, iter, 1:psib%nst), &
712 gs_scheme = te%arnoldi_gs, full_batch = te%full_batch)
722 hm%is_hermitian(), tridiagonal=hm%is_hermitian())
723 res(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo(iter, 1, ii)))
727 hm%is_hermitian(), tridiagonal=hm%is_hermitian())
728 res2(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo2(iter, 1, ii)))
733 if (all(abs(hamilt(iter + 1, iter, :)) < 1.0e4_real64*
m_epsilon))
exit
738 if (abs(hamilt(iter + 1, iter, ist)) >= 1.0e4_real64 *
m_epsilon)
then
739 norm(ist) =
m_one / abs(hamilt(iter + 1, iter, ist))
743 call batch_scal(mesh%np, norm, vb(iter+1)%p, a_full = .false.)
746 converged = iter > 3 .and. all(res < te%lanczos_tol)
747 if (converged .and. have_dt2) converged = all(res2 < te%lanczos_tol)
752 if (iter == max_order)
then
753 write(
message(1),
'(a,i5,a,es9.2)')
'Lanczos exponential expansion did not converge after ', iter, &
754 ' iterations. Residual: ', maxval(res)
757 write(
message(1),
'(a,i5)')
'Debug: Lanczos exponential iterations: ', iter
764 call batch_scal(mesh%np, expo(1,1,1:psib%nst), psib, a_full = .false.)
767 call batch_axpy(mesh%np, beta(1:psib%nst)*expo(ii,1,1:psib%nst), vb(ii)%p, psib, a_full = .false.)
772 call batch_scal(mesh%np, expo2(1,1,1:psib%nst), psib2, a_full = .false.)
774 call batch_axpy(mesh%np, beta(1:psib%nst)*expo2(ii,1,1:psib%nst), vb(ii)%p, psib2, a_full = .false.)
778 do ii = 1, max_initialized
782 safe_deallocate_a(vb)
783 safe_deallocate_a(hamilt)
784 safe_deallocate_a(expo)
785 safe_deallocate_a(expo2)
786 safe_deallocate_a(beta)
787 safe_deallocate_a(res)
788 safe_deallocate_a(res2)
789 safe_deallocate_a(norm)
814 class(
mesh_t),
intent(in) :: mesh
816 class(
batch_t),
intent(inout) :: psib
820 integer :: j, order_needed
821 complex(real64) :: coefficient
822 complex(real64),
allocatable :: coefficients(:)
823 real(real64) :: error
824 class(
batch_t),
allocatable,
target :: psi0, psi1, psi2
825 class(
batch_t),
pointer :: psi_n, psi_n1, psi_n2
826 integer,
parameter :: max_order = 200
831 call psib%clone_to(psi0)
832 call psib%clone_to(psi1)
833 call psib%clone_to(psi2)
834 call psib%copy_data_to(mesh%np, psi0)
836 order_needed = max_order
838 error = chebyshev_function%get_error(j)
839 if (error >
m_zero .and. error < te%chebyshev_tol)
then
845 call chebyshev_function%get_coefficients(j, coefficients)
848 call batch_scal(mesh%np, coefficients(0), psib)
851 call op%apply(psi0, psi1)
852 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi0, psi1)
855 call batch_axpy(mesh%np, coefficients(1), psi1, psib)
862 do j = 2, order_needed
864 call op%apply(psi_n1, psi_n)
865 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi_n1, psi_n)
870 call batch_axpy(mesh%np, coefficients(j), psi_n, psib)
873 if (mod(j, 3) == 2)
then
877 else if (mod(j, 3) == 1)
then
888 if (order_needed == max_order)
then
889 write(
message(1),
'(a,i5,a,es9.2)')
'Chebyshev exponential expansion did not converge after ', j, &
890 ' iterations. Coefficient: ', coefficient
893 write(
message(1),
'(a,i5)')
'Debug: Chebyshev exponential iterations: ', j
900 safe_deallocate_a(psi0)
901 safe_deallocate_a(psi1)
902 safe_deallocate_a(psi2)
904 safe_deallocate_a(coefficients)
918 type(
grid_t),
intent(inout) :: gr
921 real(real64),
intent(in) :: deltat
922 integer,
optional,
intent(inout) :: order
925 real(real64) :: zfact
937 do i = 1, te%exp_order
938 zfact = zfact * deltat / i
946 do ik = st%d%kpt%start, st%d%kpt%end
947 do ib = st%group%block_start, st%group%block_end
948 call batch_scal2v(gr%np, -
m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik), conjugate_xx = .false.)
949 call batch_axpy(gr%np, zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
967 do ik = st%d%kpt%start, st%d%kpt%end
968 do ib = st%group%block_start, st%group%block_end
969 call batch_axpy(gr%np, deltat, st1%group%psib(ib, ik), st%group%psib(ib, ik))
974 do i = 1, te%exp_order
975 zfact = zfact * deltat / (i+1)
983 do ik = st%d%kpt%start, st%d%kpt%end
984 do ib = st%group%block_start, st%group%block_end
985 call batch_scal2v(gr%np, -
m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik), conjugate_xx = .false.)
986 call batch_axpy(gr%np, deltat * zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
997 if (
present(order)) order = te%exp_order*st%nik*st%nst
1005 class(
mesh_t),
intent(in) :: mesh
1007 class(
batch_t),
intent(inout) :: psib
1008 real(real64),
intent(in) :: deltat
1009 integer,
intent(in) :: k
1013 complex(real64) :: deltat_
1020 if (.not. hm%is_hermitian() .and. te%exp_method ==
exp_chebyshev)
then
1021 write(
message(1),
'(a)')
'The Chebyshev expansion for the exponential will only converge if the imaginary'
1022 write(
message(2),
'(a)')
'eigenvalues are small enough compared to the span of the real eigenvalues,'
1023 write(
message(3),
'(a)')
'i.e., for ratios smaller than about 1e-3.'
1024 write(
message(4),
'(a)')
'The Lanczos method ("TDExponentialMethod = lanczos") is guaranteed to'
1025 write(
message(5),
'(a)')
'always converge in this case.'
1029 if (
present(op))
then
1035 deltat_ = cmplx(deltat,
m_zero, real64)
1037 select case (te%exp_method)
1044 else if (k == 2)
then
1047 write(
message(1),
'(a)')
'Lanczos expansion not implemented for phi_k, k > 2'
1054 else if (k == 2)
then
1057 write(
message(1),
'(a)')
'Chebyshev expansion not implemented for phi_k, k > 2'
1061 deallocate(chebyshev_function)
1064 if (.not.
present(op))
then
1065 safe_deallocate_p(op_)
1072 type(
namespace_t),
target,
intent(in) :: namespace
1073 class(
mesh_t),
target,
intent(in) :: mesh
1080 call this%init(namespace, mesh, hm)
1087 type(
namespace_t),
target,
intent(in) :: namespace
1088 class(
mesh_t),
target,
intent(in) :: mesh
1094 this%namespace => namespace
1102 class(
batch_t),
intent(inout) :: psib
1103 class(
batch_t),
intent(inout) :: hpsib
1107 call this%hm%zapply(this%namespace, this%mesh, psib, hpsib)
batchified version of the BLAS axpy routine:
batchified scale with optional conjugation:
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.
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...
type(hamiltonian_operator_t) function, pointer hamiltonian_operator_constructor(namespace, mesh, hm)
subroutine exponential_cheby_batch(te, namespace, mesh, hm, psib, chebyshev_function, op)
Calculates the exponential of the Hamiltonian through an expansion in Chebyshev polynomials.
subroutine exponential_lanczos_batch(te, namespace, mesh, hm, psib, deltat, op, inh_psib, psib2, deltat2)
Lanczos/Arnoldi procedure for the exponential of an operator.
subroutine exponential_apply_phi_batch(te, namespace, mesh, hm, psib, deltat, k, op)
subroutine exponential_apply_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, imag_time, inh_psib, op)
This routine performs the operation:
subroutine hamiltonian_operator_init(this, namespace, mesh, hm)
subroutine exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat, op, psib2, deltat2, inh_psib, phik_shift)
subroutine, public exponential_init(te, namespace, full_batch)
subroutine, public exponential_lanczos_function_batch(te, namespace, mesh, hm, psib, deltat, fun, op, psib2, deltat2)
Compute fun(H) psib, i.e. the application of a function of the Hamiltonian to a batch.
integer, parameter, public exp_taylor
integer, parameter, public exp_chebyshev
subroutine exponential_apply_single(te, namespace, mesh, hm, zpsi, ist, ik, deltat, imag_time)
Wrapper to batchified routine for applying exponential to an array.
subroutine hamiltonian_operator_apply(this, psib, hpsib)
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), parameter, 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