Octopus
exponential.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2019 M. Oliveira
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
23 use accel_oct_m
24 use batch_oct_m
26 use blas_oct_m
28 use debug_oct_m
29 use global_oct_m
30 use grid_oct_m
34 use, intrinsic :: iso_fortran_env
38 use math_oct_m
39 use mesh_oct_m
44 use parser_oct_m
48 use types_oct_m
50 use xc_oct_m
51
52 implicit none
53
54 private
55 public :: &
61 operator_t, &
64
65 integer, public, parameter :: &
66 EXP_LANCZOS = 2, &
67 exp_taylor = 3, &
69
70 type exponential_t
71 private
72 integer, public :: exp_method
73 real(real64) :: lanczos_tol
74 real(real64) :: chebyshev_tol
75 integer, public :: exp_order
76 integer :: arnoldi_gs
77 logical, public :: full_batch = .false.
78 contains
79 procedure :: apply_batch => exponential_apply_batch
80 procedure :: apply_single => exponential_apply_single
81 procedure :: apply_phi_batch => exponential_apply_phi_batch
82 end type exponential_t
83
84
85 type, abstract :: operator_t
86 type(namespace_t), pointer :: namespace
87 class(mesh_t), pointer :: mesh
88 contains
89 procedure(operator_apply), deferred :: apply
92 procedure :: is_hermitian => operator_is_hermitian
93 end type operator_t
95 abstract interface
96 subroutine operator_apply(this, psib, hpsib)
97 import operator_t
98 import batch_t
99 class(operator_t), intent(in) :: this
100 class(batch_t), intent(inout) :: psib
101 class(batch_t), intent(inout) :: hpsib
102 end subroutine operator_apply
103 end interface
104
105
106 type, extends(operator_t) :: hamiltonian_operator_t
107 class(hamiltonian_abst_t), pointer :: hm
108 contains
109 procedure :: apply => hamiltonian_operator_apply
110 procedure :: init => hamiltonian_operator_init
111 procedure :: is_hermitian => hamiltonian_operator_is_hermitian
113
114 interface hamiltonian_operator_t
115 procedure hamiltonian_operator_constructor
116 end interface hamiltonian_operator_t
117
124 type, extends(operator_t) :: sinvh_operator_t
125 class(hamiltonian_abst_t), pointer :: hm
126 contains
127 procedure :: apply => sinvh_operator_apply
128 procedure :: init => sinvh_operator_init
129 procedure :: is_hermitian => sinvh_operator_is_hermitian
130 end type sinvh_operator_t
131
132 interface sinvh_operator_t
133 procedure SinvH_operator_constructor
134 end interface sinvh_operator_t
135
136contains
138 ! ---------------------------------------------------------
139 subroutine exponential_init(te, namespace, full_batch)
140 type(exponential_t), intent(out) :: te
141 type(namespace_t), intent(in) :: namespace
142 logical, optional, intent(in) :: full_batch
143
146 !%Variable TDExponentialMethod
147 !%Type integer
148 !%Default taylor
149 !%Section Time-Dependent::Propagation
150 !%Description
151 !% Method used to numerically calculate the exponential of the Hamiltonian,
152 !% a core part of the full algorithm used to approximate the evolution
153 !% operator, specified through the variable <tt>TDPropagator</tt>.
154 !% In the case of using the Magnus method, described below, the action of the exponential
155 !% of the Magnus operator is also calculated through the algorithm specified
156 !% by this variable.
157 !%Option lanczos 2
158 !% Allows for larger time-steps.
159 !% However, the larger the time-step, the longer the computational time per time-step.
160 !% In certain cases, if the time-step is too large, the code will emit a warning
161 !% whenever it considers that the evolution may not be properly proceeding --
162 !% the Lanczos process did not converge. The method consists in a Krylov
163 !% subspace approximation of the action of the exponential
164 !% (see M. Hochbruck and C. Lubich, <i>SIAM J. Numer. Anal.</i> <b>34</b>, 1911 (1997) for details).
165 !% The performance of the method is controlled by the tolerance (controlled by <tt>TDLanczosTol</tt>).
166 !% The smaller the tolerance, the more precisely the exponential
167 !% is calculated, but also the larger the dimension of the Arnoldi
168 !% subspace. If the maximum dimension (currently 200) is not enough to meet the criterion,
169 !% the above-mentioned warning is emitted.
170 !% Be aware that the larger the required dimension of the Krylov subspace, the larger
171 !% the memory required for this method. So if you run out of memory, try to reduce
172 !% the time step.
173 !%Option taylor 3
174 !% This method amounts to a straightforward application of the definition of
175 !% the exponential of an operator, in terms of its Taylor expansion.
176 !%
177 !% <math>\exp_{\rm STD} (-i\delta t H) = \sum_{i=0}^{k} {(-i\delta t)^i\over{i!}} H^i.</math>
178 !%
179 !% The order <i>k</i> is determined by variable <tt>TDExpOrder</tt>.
180 !% Some numerical considerations from <a href=http://www.phys.washington.edu/~bertsch/num3.ps>
181 !% Jeff Giansiracusa and George F. Bertsch</a>
182 !% suggest the 4th order as especially suitable and stable.
183 !%Option chebyshev 4
184 !% In principle, the Chebyshev expansion
185 !% of the exponential represents it more accurately than the canonical or standard expansion.
186 !% <tt>TDChebyshevTol</tt> determines the tolerance to which the expansion is computed.
187 !%
188 !% There exists a closed analytic form for the coefficients of the exponential in terms
189 !% of Chebyshev polynomials:
190 !%
191 !% <math>\exp_{\rm CHEB} \left( -i\delta t H \right) = \sum_{k=0}^{\infty} (2-\delta_{k0})(-i)^{k}J_k(\delta t) T_k(H),</math>
192 !%
193 !% where <math>J_k</math> are the Bessel functions of the first kind, and H has to be previously
194 !% scaled to <math>[-1,1]</math>.
195 !% See H. Tal-Ezer and R. Kosloff, <i>J. Chem. Phys.</i> <b>81</b>,
196 !% 3967 (1984); R. Kosloff, <i>Annu. Rev. Phys. Chem.</i> <b>45</b>, 145 (1994);
197 !% C. W. Clenshaw, <i>MTAC</i> <b>9</b>, 118 (1955).
198 !%End
199 call parse_variable(namespace, 'TDExponentialMethod', exp_taylor, te%exp_method)
201 select case (te%exp_method)
202 case (exp_taylor)
203 case (exp_chebyshev)
204 !%Variable TDChebyshevTol
205 !%Type float
206 !%Default 1e-10
207 !%Section Time-Dependent::Propagation
208 !%Description
209 !% An internal tolerance variable for the Chebyshev method. The smaller, the more
210 !% precisely the exponential is calculated and the more iterations are needed, i.e.,
211 !% it becomes more expensive. The expansion is terminated once the error estimate
212 !% is below this tolerance.
213 !%End
214 call parse_variable(namespace, 'TDChebyshevTol', 1e-10_real64, te%chebyshev_tol)
215 if (te%chebyshev_tol <= m_zero) call messages_input_error(namespace, 'TDChebyshevTol')
216 case (exp_lanczos)
217 !%Variable TDLanczosTol
218 !%Type float
219 !%Default 1e-6
220 !%Section Time-Dependent::Propagation
221 !%Description
222 !% An internal tolerance variable for the Lanczos method. The smaller, the more
223 !% precisely the exponential is calculated, and also the bigger the dimension
224 !% of the Krylov subspace needed to perform the algorithm. One should carefully
225 !% make sure that this value is not too big, or else the evolution will be
226 !% wrong.
227 !%End
228 call parse_variable(namespace, 'TDLanczosTol', 1e-6_real64, te%lanczos_tol)
229 if (te%lanczos_tol <= m_zero) call messages_input_error(namespace, 'TDLanczosTol')
230
231 case default
232 call messages_input_error(namespace, 'TDExponentialMethod')
233 end select
234 call messages_print_var_option('TDExponentialMethod', te%exp_method, namespace=namespace)
235
236 if (te%exp_method == exp_taylor) then
237 !%Variable TDExpOrder
238 !%Type integer
239 !%Default 4
240 !%Section Time-Dependent::Propagation
241 !%Description
242 !% For <tt>TDExponentialMethod</tt> = <tt>taylor</tt>,
243 !% the order to which the exponential is expanded.
244 !%End
245 call parse_variable(namespace, 'TDExpOrder', default__tdexporder, te%exp_order)
246 if (te%exp_order < 2) call messages_input_error(namespace, 'TDExpOrder')
247 else
248 if (parse_is_defined(namespace, 'TDExpOrder')) then
249 message(1) = "TDExpOrder is only relevant for TDExponentialMethod = taylor"
250 call messages_fatal(1, namespace=namespace)
251 end if
252 end if
253
254 te%arnoldi_gs = option__arnoldiorthogonalization__cgs
255 if (te%exp_method == exp_lanczos) then
256 !%Variable ArnoldiOrthogonalization
257 !%Type integer
258 !%Section Time-Dependent::Propagation
259 !%Description
260 !% The orthogonalization method used for the Arnoldi procedure.
261 !% Only for TDExponentialMethod = lanczos.
262 !%Option cgs 3
263 !% Classical Gram-Schmidt (CGS) orthogonalization.
264 !% The algorithm is defined in Giraud et al., Computers and Mathematics with Applications 50, 1069 (2005).
265 !%Option drcgs 5
266 !% Classical Gram-Schmidt orthogonalization with double-step reorthogonalization.
267 !% The algorithm is taken from Giraud et al., Computers and Mathematics with Applications 50, 1069 (2005).
268 !% According to this reference, this is much more precise than CGS or MGS algorithms.
269 !%End
270 call parse_variable(namespace, 'ArnoldiOrthogonalization', option__arnoldiorthogonalization__cgs, &
271 te%arnoldi_gs)
272 end if
273
274 ! do lanczos expansion for full batch?
275 te%full_batch = optional_default(full_batch, te%full_batch)
276
277 pop_sub(exponential_init)
278 end subroutine exponential_init
279
280 ! ---------------------------------------------------------
281 subroutine exponential_copy(teo, tei)
282 type(exponential_t), intent(inout) :: teo
283 type(exponential_t), intent(in) :: tei
284
285 push_sub(exponential_copy)
286
287 teo%exp_method = tei%exp_method
288 teo%lanczos_tol = tei%lanczos_tol
289 teo%exp_order = tei%exp_order
290 teo%arnoldi_gs = tei%arnoldi_gs
291
292 pop_sub(exponential_copy)
293 end subroutine exponential_copy
294
295 ! ---------------------------------------------------------
297 subroutine exponential_apply_single(te, namespace, mesh, hm, zpsi, ist, ik, deltat, imag_time)
298 class(exponential_t), intent(inout) :: te
299 type(namespace_t), intent(in) :: namespace
300 class(mesh_t), intent(in) :: mesh
301 type(hamiltonian_elec_t), intent(inout) :: hm
302 integer, intent(in) :: ist
303 integer, intent(in) :: ik
304 complex(real64), contiguous, intent(inout) :: zpsi(:, :)
305 real(real64), intent(in) :: deltat
306 logical, optional, intent(in) :: imag_time
307
308 type(wfs_elec_t) :: psib, inh_psib
309 complex(real64), allocatable :: zpsi_inh(:, :)
310
312
313 !We apply the phase only to np points, and the phase for the np+1 to np_part points
314 !will be treated as a phase correction in the Hamiltonian
315 if (hm%phase%is_allocated()) then
316 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .false.)
317 end if
318
319 call wfs_elec_init(psib, hm%d%dim, ist, ist, zpsi, ik)
320
321 if (hamiltonian_elec_inh_term(hm)) then
322 safe_allocate(zpsi_inh(1:mesh%np_part, 1:hm%d%dim))
323 call states_elec_get_state(hm%inh_st, mesh, ist, ik, zpsi_inh(:, :))
324 call wfs_elec_init(inh_psib, hm%d%dim, ist, ist, zpsi_inh, ik)
325 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
326 imag_time=imag_time, inh_psib=inh_psib)
327 call inh_psib%end()
328 safe_deallocate_a(zpsi_inh)
329 else
330 call te%apply_batch(namespace, mesh, hm, psib, deltat, &
331 imag_time=imag_time)
332 end if
333
334 call psib%end()
335
336 if (hm%phase%is_allocated()) then
337 call hm%phase%apply_to_single(zpsi, mesh%np, hm%d%dim, ik, .true.)
338 end if
339
341 end subroutine exponential_apply_single
342
343 ! ---------------------------------------------------------
360 ! ---------------------------------------------------------
361 subroutine exponential_apply_batch(te, namespace, mesh, hm, psib, deltat, psib2, deltat2, imag_time, inh_psib, op)
362 class(exponential_t), intent(inout) :: te
363 type(namespace_t), intent(in) :: namespace
364 class(mesh_t), intent(in) :: mesh
365 class(hamiltonian_abst_t), intent(inout) :: hm
366 class(batch_t), intent(inout) :: psib
367 real(real64), intent(in) :: deltat
368 class(batch_t), optional, intent(inout) :: psib2
369 real(real64), optional, intent(in) :: deltat2
370 logical, optional, intent(in) :: imag_time
371 class(batch_t), optional, intent(inout) :: inh_psib
372 class(operator_t), target, optional, intent(in) :: op
373
374 complex(real64) :: deltat_, deltat2_
375 class(chebyshev_function_t), pointer :: chebyshev_function, chebyshev_function_dt2
376 logical :: imag_time_
377 class(operator_t), pointer :: op_
378
380 call profiling_in("EXPONENTIAL_BATCH")
381
382 assert(psib%type() == type_cmplx)
383
384 assert(present(psib2) .eqv. present(deltat2))
385 if (present(inh_psib)) then
386 assert(inh_psib%nst == psib%nst)
387 end if
388
389 if (present(op)) then
390 op_ => op
391 else
392 op_ => hamiltonian_operator_t(namespace, mesh, hm)
393 end if
394
395 deltat2_ = cmplx(optional_default(deltat2, m_zero), m_zero, real64)
396
397 imag_time_ = optional_default(imag_time, .false.)
398 if (imag_time_) then
399 deltat_ = -m_zi*deltat
400 if (present(deltat2)) deltat2_ = m_zi*deltat2
401 else
402 deltat_ = cmplx(deltat, m_zero, real64)
403 if (present(deltat2)) deltat2_ = cmplx(deltat2, m_zero, real64)
404 end if
405
406 if (.not. op_%is_hermitian() .and. te%exp_method == exp_chebyshev) then
407 write(message(1), '(a)') 'The Chebyshev expansion cannot be used for non-Hermitian operators.'
408 write(message(2), '(a)') 'Please use the Lanczos exponentiation scheme ("TDExponentialMethod = lanczos")'
409 write(message(3), '(a)') 'or the Taylor expansion ("TDExponentialMethod = taylor") method.'
410 call messages_fatal(3, namespace=namespace)
411 end if
412
413 select case (te%exp_method)
414 case (exp_taylor)
415 ! Note that delttat2_ is only initialized if deltat2 is present.
416 if (present(deltat2)) then
417 call exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat_, op_, &
418 psib2, deltat2_)
419 else
420 call exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat_, op_)
421 end if
422 if (present(inh_psib)) then
423 if (present(deltat2)) then
424 call exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat_, op_, &
425 psib2, deltat2_, inh_psib)
426 else
427 call exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat_, op_, &
428 inh_psib=inh_psib)
429 end if
430 end if
431
432 case (exp_lanczos)
433 if (present(psib2)) then
434 ! psib2 holds a copy of the starting vector; the Krylov basis is built once (driven by
435 ! psib) and both exp(-i*deltat*H) and exp(-i*deltat2*H) are reconstructed from it.
436 call psib%copy_data_to(mesh%np, psib2)
437 call exponential_lanczos_batch(te, namespace, mesh, psib, deltat_, op_, &
438 psib2=psib2, deltat2=deltat2_)
439 if (present(inh_psib)) then
440 call exponential_lanczos_batch(te, namespace, mesh, psib, deltat_, op_, inh_psib, &
441 psib2=psib2, deltat2=deltat2_)
442 end if
443 else
444 call exponential_lanczos_batch(te, namespace, mesh, psib, deltat_, op_)
445 if (present(inh_psib)) then
446 call exponential_lanczos_batch(te, namespace, mesh, psib, deltat_, op_, inh_psib)
447 end if
448 end if
449
450 case (exp_chebyshev)
451 if (present(inh_psib)) then
452 write(message(1), '(a)') 'Chebyshev exponential ("TDExponentialMethod = chebyshev")'
453 write(message(2), '(a)') 'with inhomogeneous term is not implemented'
454 call messages_fatal(2, namespace=namespace)
455 end if
456 ! initialize classes for computing coefficients
457 if (imag_time_) then
458 chebyshev_function => chebyshev_exp_imagtime_t(hm%spectral_half_span, hm%spectral_middle_point, deltat)
459 if (present(psib2)) then
460 chebyshev_function_dt2 => chebyshev_exp_imagtime_t(hm%spectral_half_span, hm%spectral_middle_point, deltat2)
461 end if
462 else
463 chebyshev_function => chebyshev_exp_t(hm%spectral_half_span, hm%spectral_middle_point, deltat)
464 if (present(psib2)) then
465 chebyshev_function_dt2 => chebyshev_exp_t(hm%spectral_half_span, hm%spectral_middle_point, deltat2)
466 end if
467 end if
468 if (present(psib2)) call psib%copy_data_to(mesh%np, psib2)
469 call exponential_cheby_batch(te, namespace, mesh, hm, psib, chebyshev_function, op_)
470 deallocate(chebyshev_function)
471 if (present(psib2)) then
472 call exponential_cheby_batch(te, namespace, mesh, hm, psib2, chebyshev_function_dt2, op_)
473 deallocate(chebyshev_function_dt2)
474 end if
475
476 end select
477
478 if (.not.present(op)) then
479 safe_deallocate_p(op_)
480 end if
481
482 call profiling_out("EXPONENTIAL_BATCH")
484 end subroutine exponential_apply_batch
485
486 ! ---------------------------------------------------------
487 subroutine exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat, op, psib2, deltat2, inh_psib, phik_shift)
488 type(exponential_t), intent(inout) :: te
489 type(namespace_t), intent(in) :: namespace
490 class(mesh_t), intent(in) :: mesh
491 class(hamiltonian_abst_t), intent(inout) :: hm
492 class(batch_t), intent(inout) :: psib
493 complex(real64), intent(in) :: deltat
494 class(operator_t), intent(in) :: op
495 class(batch_t), optional, intent(inout) :: psib2
496 complex(real64), optional, intent(in) :: deltat2
497 class(batch_t), optional, intent(inout) :: inh_psib
498 integer, optional, intent(in) :: phik_shift
499
500 complex(real64) :: zfact, zfact2
501 integer :: iter, denom, phik_shift_
502 logical :: zfact_is_real
503 class(batch_t), allocatable :: psi1b, hpsi1b
504
506 call profiling_in("EXP_TAYLOR_BATCH")
507
508 call psib%clone_to(psi1b)
509 call psib%clone_to(hpsi1b)
510
511 zfact = m_z1
512 zfact2 = m_z1
513 zfact_is_real = abs(deltat-real(deltat, real64)) < m_epsilon
514
515 if (present(psib2)) call psib%copy_data_to(mesh%np, psib2)
516
517 if (present(inh_psib)) then
518 zfact = zfact*deltat
519 call batch_axpy(mesh%np, real(zfact, real64), inh_psib, psib)
520
521 if (present(psib2)) then
522 zfact2 = zfact2*deltat2
523 call batch_axpy(mesh%np, real(zfact2, real64), inh_psib, psib2)
524 end if
525 end if
526
527 ! shift the denominator by this shift for the phi_k functions
528 phik_shift_ = optional_default(phik_shift, 0)
529
530 do iter = 1, te%exp_order
531 denom = iter+phik_shift_
532 if (present(inh_psib)) denom = denom + 1
533 zfact = zfact*(-m_zi*deltat)/denom
534 if (present(deltat2)) zfact2 = zfact2*(-m_zi*deltat2)/denom
535 zfact_is_real = .not. zfact_is_real
536 ! FIXME: need a test here for runaway exponential, e.g. for too large dt.
537 ! in runaway case the problem is really hard to trace back: the positions
538 ! go haywire on the first step of dynamics (often NaN) and with debugging options
539 ! the code stops in ZAXPY below without saying why.
540
541 if (iter /= 1) then
542 call op%apply(psi1b, hpsi1b)
543 else
544 if (present(inh_psib)) then
545 call op%apply(inh_psib, hpsi1b)
546 else
547 call op%apply(psib, hpsi1b)
548 end if
549 end if
550
551 if (zfact_is_real) then
552 call batch_axpy(mesh%np, real(zfact, real64), hpsi1b, psib)
553 if (present(psib2)) call batch_axpy(mesh%np, real(zfact2, real64), hpsi1b, psib2)
554 else
555 call batch_axpy(mesh%np, zfact, hpsi1b, psib)
556 if (present(psib2)) call batch_axpy(mesh%np, zfact2, hpsi1b, psib2)
557 end if
558
559 if (iter /= te%exp_order) call hpsi1b%copy_data_to(mesh%np, psi1b)
560
561 end do
562
563 call psi1b%end()
564 call hpsi1b%end()
565 safe_deallocate_a(psi1b)
566 safe_deallocate_a(hpsi1b)
567
568 call profiling_out("EXP_TAYLOR_BATCH")
571
575 subroutine exponential_lanczos_batch(te, namespace, mesh, psib, deltat, op, inh_psib, psib2, deltat2)
576 type(exponential_t), intent(inout) :: te
577 type(namespace_t), intent(in) :: namespace
578 class(mesh_t), intent(in) :: mesh
579 class(batch_t), intent(inout) :: psib
580 complex(real64), intent(in) :: deltat
581 class(operator_t), intent(in) :: op
582 class(batch_t), optional, intent(in) :: inh_psib
583 class(batch_t), optional, intent(inout) :: psib2
584 complex(real64), optional, intent(in) :: deltat2
585
586 class(batch_t), allocatable :: tmpb, tmpb2
587
589
590 assert(present(psib2) .eqv. present(deltat2))
591
592 if (present(inh_psib)) then
593 call inh_psib%clone_to(tmpb, copy_data=.true.)
594 if (present(psib2)) then
595 ! psib = psib + deltat * phi1(-i*deltat *H) inh_psib
596 ! psib2 = psib2 + deltat2 * phi1(-i*deltat2*H) inh_psib (shared Krylov basis)
597 call inh_psib%clone_to(tmpb2, copy_data=.true.)
598 call exponential_lanczos_function_batch(te, namespace, mesh, tmpb, deltat, phi1, op, &
599 psib2=tmpb2, deltat2=deltat2)
600 call batch_axpy(mesh%np, real(deltat, real64), tmpb, psib)
601 call batch_axpy(mesh%np, real(deltat2, real64), tmpb2, psib2)
602 call tmpb2%end()
603 safe_deallocate_a(tmpb2)
604 else
605 ! psib = psib + deltat * phi1(-i*deltat*H) inh_psib
606 call exponential_lanczos_function_batch(te, namespace, mesh, tmpb, deltat, phi1, op)
607 call batch_axpy(mesh%np, real(deltat, real64), tmpb, psib)
608 end if
609 call tmpb%end()
610 safe_deallocate_a(tmpb)
611 else
612 if (present(psib2)) then
613 call exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat, exponential, op, &
614 psib2=psib2, deltat2=deltat2)
615 else
616 call exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat, exponential, op)
617 end if
618 end if
619
621 end subroutine exponential_lanczos_batch
622
623 ! ---------------------------------------------------------
637 subroutine exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat, fun, op, psib2, deltat2)
638 type(exponential_t), intent(inout) :: te
639 type(namespace_t), intent(in) :: namespace
640 class(mesh_t), intent(in) :: mesh
641 class(batch_t), intent(inout) :: psib
642 complex(real64), intent(in) :: deltat
643 interface
644 complex(real64) function fun(z)
645 import real64
646 complex(real64), intent(in) :: z
647 end
648 end interface
649 class(operator_t), intent(in) :: op
650 class(batch_t), optional, intent(inout) :: psib2
651 complex(real64), optional, intent(in) :: deltat2
652
653 integer :: iter, l, ii, ist, max_initialized
654 complex(real64), allocatable :: hamilt(:,:,:), expo(:,:,:), expo2(:,:,:)
655 complex(real64), allocatable :: hamilt_tmp(:,:,:), coef(:,:), coef2(:,:)
656 real(real64), allocatable :: beta(:), res(:), res2(:), norm(:)
657 integer, parameter :: max_order = 200
659 integer, parameter :: order_initial = 16
660 integer :: order_alloc
661 type(batch_p_t), allocatable :: vb(:) ! Krylov subspace vectors
662 logical :: have_dt2, converged, breakdown
663
665 call profiling_in("EXP_LANCZOS_FUN_BATCH")
666
667 if (te%exp_method /= exp_lanczos) then
668 message(1) = "The exponential method needs to be set to Lanzcos (TDExponentialMethod=lanczos)."
669 call messages_fatal(1)
670 end if
671
672 ! Optionally, a second exponential fun(deltat2*H) psib is computed reusing the same
673 ! Krylov basis and projected matrix (they do not depend on deltat), and written to psib2.
674 ! psib2 must already hold a copy of the input psib on entry (used as the starting vector
675 ! for the reconstruction), which is what the caller provides.
676 have_dt2 = present(psib2)
677 assert(present(psib2) .eqv. present(deltat2))
678 if (have_dt2) then
679 assert(psib2%nst == psib%nst)
680 end if
681
682 safe_allocate(beta(1:psib%nst))
683 safe_allocate(res(1:psib%nst))
684 safe_allocate(norm(1:psib%nst))
685 ! the residual is only computed from iteration 4 on; the non-convergence
686 ! message below prints maxval(res), so it must be defined even if the loop
687 ! somehow ends earlier
688 res = m_huge
689 safe_allocate(vb(1:max_order))
690 call psib%clone_to(vb(1)%p)
691 max_initialized = 1
692
693 ! Initialise starting Lanczos vector, v_1, from input wave function
694 call psib%copy_data_to(mesh%np, vb(1)%p, async=.true.)
695
696 ! Normalise v_1
697 ! Note, this is not the Lanczos coefficient
698 call mesh_batch_nrm2(mesh, vb(1)%p, beta)
699 if (te%full_batch) beta = norm2(beta)
700
701 ! If we have a null vector, no need to compute the action of the exponential.
702 if (all(abs(beta) <= 1.0e-12_real64)) then
703 safe_deallocate_a(beta)
704 safe_deallocate_a(res)
705 safe_deallocate_a(norm)
706 call vb(1)%p%end()
707 safe_deallocate_a(vb)
708 call profiling_out("EXP_LANCZOS_FUN_BATCH")
710 return
711 end if
712
713 call batch_scal(mesh%np, m_one/beta, vb(1)%p, a_full = .false.)
714
715 order_alloc = order_initial
716 safe_allocate(hamilt(1:order_alloc+1, 1:order_alloc+1, 1:psib%nst))
717 safe_allocate( expo(1:order_alloc+1, 1:order_alloc+1, 1:psib%nst))
718 if (have_dt2) then
719 safe_allocate(expo2(1:order_alloc+1, 1:order_alloc+1, 1:psib%nst))
720 safe_allocate(res2(1:psib%nst))
721 res2 = m_huge
722 end if
723
724 ! Lanczos loop
725 do iter = 1, max_order-1
726 ! Grow the projected matrices if the subspace outgrows them
727 if (iter + 1 > order_alloc) then
728 safe_allocate(hamilt_tmp(1:2*order_alloc+1, 1:2*order_alloc+1, 1:psib%nst))
729 hamilt_tmp = m_z0
730 hamilt_tmp(1:order_alloc+1, 1:order_alloc+1, :) = hamilt(:, :, :)
731 safe_deallocate_a(hamilt)
732 call move_alloc(hamilt_tmp, hamilt)
733 ! expo and expo2 are written before they are read, so nothing to keep
734 order_alloc = min(2*order_alloc, max_order)
735 safe_deallocate_a(expo)
736 safe_allocate(expo(1:order_alloc+1, 1:order_alloc+1, 1:psib%nst))
737 if (have_dt2) then
738 safe_deallocate_a(expo2)
739 safe_allocate(expo2(1:order_alloc+1, 1:order_alloc+1, 1:psib%nst))
740 end if
741 end if
742
743 call psib%clone_to(vb(iter + 1)%p)
744 max_initialized = iter + 1
745
746 ! Apply the operator (default is Hamiltonian), w = H v_j
747 call op%apply(vb(iter)%p, vb(iter+1)%p)
748
749 ! We use either the Lanczos method (Hermitian case) or the Arnoldi method
750 if (op%is_hermitian()) then
751 ! The Lanczos projection is tridiagonal: T(i,j) = 0 for i < j-1.
752 hamilt(1:max(iter-2, 1), iter, 1:psib%nst) = m_zero
753 if (iter > 1) then
754 ! T(j-1,j) = beta_j
755 hamilt(iter-1, iter, 1:psib%nst) = hamilt(iter, iter-1, 1:psib%nst)
756 ! w = H v_j - beta_j v_{j-1}
757 call batch_axpy(mesh%np, -hamilt(iter-1, iter, 1:psib%nst), vb(iter-1)%p, vb(iter+1)%p, a_full = .false.)
758 end if
759 ! Only the projection onto v_j remains for the call below.
760 l = iter
761 else
762 ! Arnoldi projects against every existing basis vector v_1,...,v_j
763 l = 1
764 if (iter > 2) then
765 ! The projected matrix is upper Hessenberg: H(j,1:j-2) = 0
766 hamilt(iter, 1:iter-2, 1:psib%nst) = m_zero
767 end if
768 end if
769
770 ! Orthogonalize against previous vectors, where vb(iter+1)%p defines w on entry
771 ! For Lanczos, this routine computes 3 things:
772 ! (overlap): alpha_j = <v_j, w> returned to hamilt(j, j, :)
773 ! (norm): beta_{j+1} = ||r_j|| returned to hamilt(j+1, j, :)
774 ! (residual): r_j = w - alpha_j v_j returned in vb(j+1)%p, not normalised
775 ! For Arnoldi, this routine computes 3 things:
776 ! (overlap): h_{1:j,j} = <v_{1:j}, w> returned to hamilt(1:j, j, :)
777 ! (norm): h_{j+1,j} = ||r_j|| returned to hamilt(j+1, j, :)
778 ! (residual): r_j = w - sum_{i=1}^j h_{i,j} v_i in vb(j+1)%p, not normalised
779 call zmesh_batch_orthogonalization(mesh, iter - l + 1, vb(l:iter), vb(iter+1)%p, &
780 normalize = .false., overlap = hamilt(l:iter, iter, 1:psib%nst), norm = hamilt(iter + 1, iter, 1:psib%nst), &
781 gs_scheme = te%arnoldi_gs, full_batch = te%full_batch)
782
783 ! We now estimate the error we made. This is given by the formula denoted
784 ! Er2 in Sec. 5.2.
785 breakdown = all(abs(hamilt(iter + 1, iter, :)) < 1.0e4_real64*m_epsilon) ! "Happy breakdown"
786
787 ! We now need to compute exp(Hm), where Hm is the projection of the linear transformation
788 ! of the Hamiltonian onto the Krylov subspace Km
789 ! See Eq. 4
790 !
791 ! Note that in the Hermitian case, we use the Lanczos algorithm that requires
792 ! only a tridiagonal matrix. Else we have an upper Hessenberg matrix.
793 !
794 ! Compute the exponential only if it is potentially used: for happy breakdown and
795 ! for convergence at iteration >= 4. This saves a lot of time especially for small
796 ! iteration counts.
797 if (iter > 3 .or. breakdown) then
798 if (op%is_hermitian()) then
799 ! Only the first column of fun(T) is used; one real eigendecomposition serves both time steps
800 do ii = 1, psib%nst
801 if (have_dt2) then
802 call lalg_tridiagonal_function_first_column(iter, hamilt(:,:,ii), fun, -m_zi*deltat, expo(:,1,ii), &
803 -m_zi*deltat2, expo2(:,1,ii))
804 res2(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo2(iter, 1, ii)))
805 else
806 call lalg_tridiagonal_function_first_column(iter, hamilt(:,:,ii), fun, -m_zi*deltat, expo(:,1,ii))
807 end if
808 res(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo(iter, 1, ii)))
809 end do !ii
810 else
811 ! Same for the Arnoldi projection, with one complex eigendecomposition and one linear solve
812 do ii = 1, psib%nst
813 if (have_dt2) then
814 call lalg_hessenberg_function_first_column(iter, hamilt(:,:,ii), fun, -m_zi*deltat, expo(:,1,ii), &
815 -m_zi*deltat2, expo2(:,1,ii))
816 res2(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo2(iter, 1, ii)))
817 else
818 call lalg_hessenberg_function_first_column(iter, hamilt(:,:,ii), fun, -m_zi*deltat, expo(:,1,ii))
819 end if
820 res(ii) = abs(hamilt(iter + 1, iter, ii) * abs(expo(iter, 1, ii)))
821 end do !ii
822 end if
823 end if
824
825 if (breakdown) exit
826
827 ! Compute 1/beta_{j+1}
828 ! We normalize only if the norm is non-zero
829 ! see http://www.netlib.org/utk/people/JackDongarra/etemplates/node216.html#alg:arn0
830 norm = m_one
831 do ist = 1, psib%nst
832 if (abs(hamilt(iter + 1, iter, ist)) >= 1.0e4_real64 * m_epsilon) then
833 norm(ist) = m_one / abs(hamilt(iter + 1, iter, ist))
834 end if
835 end do
836
837 ! v_{j+1} = r_j / beta_{j+1}
838 call batch_scal(mesh%np, norm, vb(iter+1)%p, a_full = .false.)
839
840 ! When a second exponential shares this basis, require both to be
841 ! converged.
842 converged = .false.
843 if (iter > 3) then
844 converged = all(res < te%lanczos_tol)
845 if (converged .and. have_dt2) converged = all(res2 < te%lanczos_tol)
846 end if
847 if (converged) exit
848
849 end do !iter
850
851 if (iter == max_order) then ! Here one should consider the possibility of the happy breakdown.
852 write(message(1),'(a,i5,a,es9.2)') 'Lanczos exponential expansion did not converge after ', iter, &
853 ' iterations. Residual: ', maxval(res)
854 call messages_warning(1, namespace=namespace)
855 ! expo was last evaluated for the subspace of the final loop iteration
856 iter = max_order - 1
857 else
858 write(message(1),'(a,i5)') 'Debug: Lanczos exponential iterations: ', iter
859 call messages_info(1, namespace=namespace, debug_only=.true.)
860 end if
861
862 ! See Eq. 4 for the expression here
863 ! zpsi = nrm * V * expo(1:iter, 1) = nrm * V * expo * V^(T) * zpsi
864 ! psib (and, on entry, psib2) still holds the original starting vector = beta * vb(1).
865 ! Both exponentials are reconstructed from the same Krylov basis vb.
866 safe_allocate(coef(1:iter-1, 1:psib%nst))
867 do ii = 1, psib%nst
868 coef(1:iter-1, ii) = beta(ii)*expo(2:iter, 1, ii)
869 end do
870 if (have_dt2) then
871 safe_allocate(coef2(1:iter-1, 1:psib%nst))
872 do ii = 1, psib%nst
873 coef2(1:iter-1, ii) = beta(ii)*expo2(2:iter, 1, ii)
874 end do
875 call batch_gemv(mesh%np, vb(2:iter), coef, expo(1,1,1:psib%nst), psib, &
876 coef2, expo2(1,1,1:psib%nst), psib2)
877 safe_deallocate_a(coef2)
878 else
879 call batch_gemv(mesh%np, vb(2:iter), coef, expo(1,1,1:psib%nst), psib)
880 end if
881 safe_deallocate_a(coef)
882
883 do ii = 1, max_initialized
884 call vb(ii)%p%end()
885 end do
886
887 safe_deallocate_a(vb)
888 safe_deallocate_a(hamilt)
889 safe_deallocate_a(hamilt_tmp)
890 safe_deallocate_a(expo)
891 safe_deallocate_a(expo2)
892 safe_deallocate_a(beta)
893 safe_deallocate_a(res)
894 safe_deallocate_a(res2)
895 safe_deallocate_a(norm)
896
897 call accel_finish()
898
899 call profiling_out("EXP_LANCZOS_FUN_BATCH")
900
903
904
905 ! ---------------------------------------------------------
917 subroutine exponential_cheby_batch(te, namespace, mesh, hm, psib, chebyshev_function, op)
918 type(exponential_t), intent(inout) :: te
919 type(namespace_t), intent(in) :: namespace
920 class(mesh_t), intent(in) :: mesh
921 class(hamiltonian_abst_t), intent(inout) :: hm
922 class(batch_t), intent(inout) :: psib
923 class(chebyshev_function_t), intent(in) :: chebyshev_function
924 class(operator_t), intent(in) :: op
925
926 integer :: j, order_needed
927 complex(real64) :: coefficient
928 complex(real64), allocatable :: coefficients(:)
929 real(real64) :: error
930 class(batch_t), allocatable, target :: psi0, psi1, psi2
931 class(batch_t), pointer :: psi_n, psi_n1, psi_n2
932 integer, parameter :: max_order = 200
933
935 call profiling_in("EXP_CHEBY_BATCH")
936
937 call psib%clone_to(psi0)
938 call psib%clone_to(psi1)
939 call psib%clone_to(psi2)
940 call psib%copy_data_to(mesh%np, psi0)
941
942 order_needed = max_order
943 do j = 1, max_order
944 error = chebyshev_function%get_error(j)
945 if (error > m_zero .and. error < te%chebyshev_tol) then
946 order_needed = j
947 exit
948 end if
949 end do
950
951 call chebyshev_function%get_coefficients(j, coefficients)
952
953 ! zero-order term
954 call batch_scal(mesh%np, coefficients(0), psib)
955 ! first-order term
956 ! shifted Hamiltonian
957 call op%apply(psi0, psi1)
958 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi0, psi1)
959 call batch_scal(mesh%np, m_one/hm%spectral_half_span, psi1)
960 ! accumulate result
961 call batch_axpy(mesh%np, coefficients(1), psi1, psib)
962
963 ! use pointers to avoid copies
964 psi_n => psi2
965 psi_n1 => psi1
966 psi_n2 => psi0
967
968 do j = 2, order_needed
969 ! compute shifted Hamiltonian and Chebyshev recurrence formula
970 call op%apply(psi_n1, psi_n)
971 call batch_axpy(mesh%np, -hm%spectral_middle_point, psi_n1, psi_n)
972 call batch_xpay(mesh%np, psi_n2, -m_two/hm%spectral_half_span, psi_n)
973 call batch_scal(mesh%np, -m_one, psi_n)
974
975 ! accumulate result
976 call batch_axpy(mesh%np, coefficients(j), psi_n, psib)
977
978 ! shift pointers for the three-term recurrence, this avoids copies
979 if (mod(j, 3) == 2) then
980 psi_n => psi0
981 psi_n1 => psi2
982 psi_n2 => psi1
983 else if (mod(j, 3) == 1) then
984 psi_n => psi2
985 psi_n1 => psi1
986 psi_n2 => psi0
987 else
988 psi_n => psi1
989 psi_n1 => psi0
990 psi_n2 => psi2
991 end if
992 end do
993
994 if (order_needed == max_order) then
995 write(message(1),'(a,i5,a,es9.2)') 'Chebyshev exponential expansion did not converge after ', j, &
996 ' iterations. Coefficient: ', coefficient
997 call messages_warning(1, namespace=namespace)
998 else
999 write(message(1),'(a,i5)') 'Debug: Chebyshev exponential iterations: ', j
1000 call messages_info(1, namespace=namespace, debug_only=.true.)
1001 end if
1002
1003 call psi0%end()
1004 call psi1%end()
1005 call psi2%end()
1006 safe_deallocate_a(psi0)
1007 safe_deallocate_a(psi1)
1008 safe_deallocate_a(psi2)
1009
1010 safe_deallocate_a(coefficients)
1011
1012 call profiling_out("EXP_CHEBY_BATCH")
1013
1015 end subroutine exponential_cheby_batch
1016
1017 ! ---------------------------------------------------------
1021 subroutine exponential_apply_all(te, namespace, gr, hm, st, deltat, order)
1022 type(exponential_t), intent(inout) :: te
1023 type(namespace_t), intent(in) :: namespace
1024 type(grid_t), intent(inout) :: gr
1025 type(hamiltonian_elec_t), intent(inout) :: hm
1026 type(states_elec_t), intent(inout) :: st
1027 real(real64), intent(in) :: deltat
1028 integer, optional, intent(inout) :: order
1029
1030 integer :: ik, ib, i
1031 real(real64) :: zfact
1032
1033 type(states_elec_t) :: st1, hst1
1034
1035 push_sub(exponential_apply_all)
1036
1037 assert(te%exp_method == exp_taylor)
1038
1039 call states_elec_copy(st1, st)
1040 call states_elec_copy(hst1, st)
1041
1042 zfact = m_one
1043 do i = 1, te%exp_order
1044 zfact = zfact * deltat / i
1045
1046 if (i == 1) then
1047 call zhamiltonian_elec_apply_all(hm, namespace, gr, st, hst1)
1048 else
1049 call zhamiltonian_elec_apply_all(hm, namespace, gr, st1, hst1)
1050 end if
1051
1052 do ik = st%d%kpt%start, st%d%kpt%end
1053 do ib = st%group%block_start, st%group%block_end
1054 call batch_scal2v(gr%np, -m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik), conjugate_xx = .false.)
1055 call batch_axpy(gr%np, zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
1056 end do
1057 end do
1058
1059 end do
1060 ! End of Taylor expansion loop.
1061
1062 call states_elec_end(st1)
1063 call states_elec_end(hst1)
1064
1065 ! We now add the inhomogeneous part, if present.
1066 if (hamiltonian_elec_inh_term(hm)) then
1067 !write(*, *) 'Now we apply the inhomogeneous term...'
1068
1069 call states_elec_copy(st1, hm%inh_st)
1070 call states_elec_copy(hst1, hm%inh_st)
1071
1072
1073 do ik = st%d%kpt%start, st%d%kpt%end
1074 do ib = st%group%block_start, st%group%block_end
1075 call batch_axpy(gr%np, deltat, st1%group%psib(ib, ik), st%group%psib(ib, ik))
1076 end do
1077 end do
1078
1079 zfact = m_one
1080 do i = 1, te%exp_order
1081 zfact = zfact * deltat / (i+1)
1082
1083 if (i == 1) then
1084 call zhamiltonian_elec_apply_all(hm, namespace, gr, hm%inh_st, hst1)
1085 else
1086 call zhamiltonian_elec_apply_all(hm, namespace, gr, st1, hst1)
1087 end if
1088
1089 do ik = st%d%kpt%start, st%d%kpt%end
1090 do ib = st%group%block_start, st%group%block_end
1091 call batch_scal2v(gr%np, -m_zi, hst1%group%psib(ib, ik), st1%group%psib(ib, ik), conjugate_xx = .false.)
1092 call batch_axpy(gr%np, deltat * zfact, st1%group%psib(ib, ik), st%group%psib(ib, ik))
1093 end do
1094 end do
1095
1096 end do
1097
1098 call states_elec_end(st1)
1099 call states_elec_end(hst1)
1100
1101 end if
1102
1103 if (present(order)) order = te%exp_order*st%nik*st%nst ! This should be the correct number
1104
1105 pop_sub(exponential_apply_all)
1106 end subroutine exponential_apply_all
1107
1108 subroutine exponential_apply_phi_batch(te, namespace, mesh, hm, psib, deltat, k, op)
1109 class(exponential_t), intent(inout) :: te
1110 type(namespace_t), intent(in) :: namespace
1111 class(mesh_t), intent(in) :: mesh
1112 class(hamiltonian_abst_t), intent(inout) :: hm
1113 class(batch_t), intent(inout) :: psib
1114 real(real64), intent(in) :: deltat
1115 integer, intent(in) :: k
1116 class(operator_t), target,optional, intent(in) :: op
1117
1118 class(chebyshev_function_t), pointer :: chebyshev_function
1119 complex(real64) :: deltat_
1120 class(operator_t), pointer :: op_
1121
1122 push_sub_with_profile(exponential_apply_phi_batch)
1123
1124 assert(psib%type() == type_cmplx)
1125
1126 if (present(op)) then
1127 op_ => op
1128 else
1129 op_ => hamiltonian_operator_t(namespace, mesh, hm)
1130 end if
1131
1132 if (.not. op_%is_hermitian() .and. te%exp_method == exp_chebyshev) then
1133 write(message(1), '(a)') 'The Chebyshev expansion for the exponential will only converge if the imaginary'
1134 write(message(2), '(a)') 'eigenvalues are small enough compared to the span of the real eigenvalues,'
1135 write(message(3), '(a)') 'i.e., for ratios smaller than about 1e-3.'
1136 write(message(4), '(a)') 'The Lanczos method ("TDExponentialMethod = lanczos") is guaranteed to'
1137 write(message(5), '(a)') 'always converge in this case.'
1138 call messages_warning(5, namespace=namespace)
1139 end if
1140
1141 deltat_ = cmplx(deltat, m_zero, real64)
1142
1143 select case (te%exp_method)
1144 case (exp_taylor)
1145 call exponential_taylor_series_batch(te, namespace, mesh, hm, psib, deltat_, op_, phik_shift=k)
1146
1147 case (exp_lanczos)
1148 if (k == 1) then
1149 call exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat_, phi1, op_)
1150 else if (k == 2) then
1151 call exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat_, phi2, op_)
1152 else
1153 write(message(1), '(a)') 'Lanczos expansion not implemented for phi_k, k > 2'
1154 call messages_fatal(1, namespace=namespace)
1155 end if
1156
1157 case (exp_chebyshev)
1158 if (k == 1) then
1159 chebyshev_function => chebyshev_numerical_t(hm%spectral_half_span, hm%spectral_middle_point, deltat, phi1)
1160 else if (k == 2) then
1161 chebyshev_function => chebyshev_numerical_t(hm%spectral_half_span, hm%spectral_middle_point, deltat, phi2)
1162 else
1163 write(message(1), '(a)') 'Chebyshev expansion not implemented for phi_k, k > 2'
1164 call messages_fatal(1, namespace=namespace)
1165 end if
1166 call exponential_cheby_batch(te, namespace, mesh, hm, psib, chebyshev_function, op_)
1167 deallocate(chebyshev_function)
1168 end select
1169
1170 if (.not.present(op)) then
1171 safe_deallocate_p(op_)
1172 end if
1173
1174 pop_sub_with_profile(exponential_apply_phi_batch)
1175 end subroutine exponential_apply_phi_batch
1176
1177 function hamiltonian_operator_constructor(namespace, mesh, hm) result(this)
1178 type(namespace_t), target, intent(in) :: namespace
1179 class(mesh_t), target, intent(in) :: mesh
1180 class(hamiltonian_abst_t), target, intent(in) :: hm
1181 type(hamiltonian_operator_t), pointer :: this
1182
1184
1185 allocate(this)
1186 call this%init(namespace, mesh, hm)
1187
1190
1191 subroutine hamiltonian_operator_init(this, namespace, mesh, hm)
1192 class(hamiltonian_operator_t), intent(inout) :: this
1193 type(namespace_t), target, intent(in) :: namespace
1194 class(mesh_t), target, intent(in) :: mesh
1195 class(hamiltonian_abst_t), target, intent(in) :: hm
1196
1198
1199 this%mesh => mesh
1200 this%namespace => namespace
1201 this%hm => hm
1202
1204 end subroutine hamiltonian_operator_init
1205
1206 subroutine hamiltonian_operator_apply(this, psib, hpsib)
1207 class(hamiltonian_operator_t), intent(in) :: this
1208 class(batch_t), intent(inout) :: psib
1209 class(batch_t), intent(inout) :: hpsib
1210
1212
1213 call this%hm%zapply(this%namespace, this%mesh, psib, hpsib)
1214
1216 end subroutine hamiltonian_operator_apply
1217
1218 ! ---------------------------------------------------------
1219 logical function operator_is_hermitian(this)
1220 class(operator_t), intent(in) :: this
1221
1223 end function operator_is_hermitian
1224
1225 ! ---------------------------------------------------------
1226 logical function hamiltonian_operator_is_hermitian(this)
1227 class(hamiltonian_operator_t), intent(in) :: this
1228
1229 hamiltonian_operator_is_hermitian = this%hm%is_hermitian()
1231
1232 ! ---------------------------------------------------------
1233 function sinvh_operator_constructor(namespace, mesh, hm) result(this)
1234 type(namespace_t), target, intent(in) :: namespace
1235 class(mesh_t), target, intent(in) :: mesh
1236 class(hamiltonian_abst_t), target, intent(in) :: hm
1237 type(sinvh_operator_t), pointer :: this
1238
1240
1241 allocate(this)
1242 call this%init(namespace, mesh, hm)
1243
1245 end function sinvh_operator_constructor
1246
1247 ! ---------------------------------------------------------
1248 subroutine sinvh_operator_init(this, namespace, mesh, hm)
1249 class(sinvh_operator_t), intent(inout) :: this
1250 type(namespace_t), target, intent(in) :: namespace
1251 class(mesh_t), target, intent(in) :: mesh
1252 class(hamiltonian_abst_t), target, intent(in) :: hm
1253
1254 push_sub(sinvh_operator_init)
1255
1256 this%mesh => mesh
1257 this%namespace => namespace
1258 this%hm => hm
1259
1260 pop_sub(sinvh_operator_init)
1261 end subroutine sinvh_operator_init
1262
1263 ! ---------------------------------------------------------
1265 subroutine sinvh_operator_apply(this, psib, hpsib)
1266 class(sinvh_operator_t), intent(in) :: this
1267 class(batch_t), intent(inout) :: psib
1268 class(batch_t), intent(inout) :: hpsib
1269
1270 push_sub(sinvh_operator_apply)
1271
1272 select type (psib)
1273 class is (wfs_elec_t)
1274 select type (hpsib)
1275 class is (wfs_elec_t)
1276 select type (hm => this%hm)
1277 class is (hamiltonian_elec_t)
1278 call zhamiltonian_elec_apply_sinvh_batch(hm, this%namespace, this%mesh, psib, hpsib)
1279 class default
1280 ! S^{-1} = 1 for non-electronic Hamiltonians: just apply H
1281 call this%hm%zapply(this%namespace, this%mesh, psib, hpsib)
1282 end select
1283 class default
1284 message(1) = "SinvH_operator_apply requires wfs_elec_t batches."
1285 call messages_fatal(1)
1286 end select
1287 class default
1288 message(1) = "SinvH_operator_apply requires wfs_elec_t batches."
1289 call messages_fatal(1)
1290 end select
1292 pop_sub(sinvh_operator_apply)
1293 end subroutine sinvh_operator_apply
1294
1295 ! ---------------------------------------------------------
1296 logical function sinvh_operator_is_hermitian(this)
1297 class(sinvh_operator_t), intent(in) :: this
1299 ! A = S^{-1}H is self-adjoint in the S inner product, NOT the Euclidean one
1301 end function sinvh_operator_is_hermitian
1302
1303end module exponential_oct_m
1304
1305!! Local Variables:
1306!! mode: f90
1307!! coding: utf-8
1308!! End:
batchified version of the BLAS axpy routine:
Definition: batch_ops.F90:139
batchified linear combination:
Definition: batch_ops.F90:163
batchified scale with optional conjugation:
Definition: batch_ops.F90:169
scale a batch by a constant or vector
Definition: batch_ops.F90:149
batchified version of
Definition: batch_ops.F90:175
subroutine, public accel_finish()
Definition: accel.F90:1104
This module implements batches of mesh functions.
Definition: batch.F90:112
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:95
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:97
logical function hamiltonian_operator_is_hermitian(this)
logical function operator_is_hermitian(this)
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 exponential_lanczos_batch(te, namespace, mesh, psib, deltat, op, inh_psib, psib2, deltat2)
Lanczos/Arnoldi procedure for the exponential of an operator.
subroutine sinvh_operator_init(this, namespace, mesh, hm)
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.
type(sinvh_operator_t) function, pointer sinvh_operator_constructor(namespace, mesh, hm)
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, public exponential_lanczos_function_batch(te, namespace, mesh, psib, deltat, fun, op, psib2, deltat2)
Compute fun(H) psib, i.e. the application of a function of the Hamiltonian to a batch.
logical function sinvh_operator_is_hermitian(this)
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)
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 sinvh_operator_apply(this, psib, hpsib)
Apply A = S^{-1} H, the operator propagated for ultrasoft/PAW.
subroutine hamiltonian_operator_apply(this, psib, hpsib)
real(real64), parameter, public m_two
Definition: global.F90:175
real(real64), parameter, public m_huge
Definition: global.F90:191
real(real64), parameter, public m_zero
Definition: global.F90:173
complex(real64), parameter, public m_z0
Definition: global.F90:183
complex(real64), parameter, public m_zi
Definition: global.F90:187
real(real64), parameter, public m_epsilon
Definition: global.F90:189
complex(real64), parameter, public m_z1
Definition: global.F90:184
real(real64), parameter, public m_one
Definition: global.F90:174
This module implements the underlying real-space grid.
Definition: grid.F90:96
This module defines an abstract class for Hamiltonians.
subroutine, public zhamiltonian_elec_apply_all(hm, namespace, gr, st, hst)
subroutine, public zhamiltonian_elec_apply_sinvh_batch(hm, namespace, mesh, psib, hspsib, terms, set_bc, set_phase)
Apply the operator A = S^{-1} H to a batch (for ultrasoft/PAW).
pure logical function, public hamiltonian_elec_inh_term(hm)
subroutine, public lalg_hessenberg_function_first_column(n, h, fun, factor, col, factor2, col2)
First column of fun(factor*H) for a diagonalizable complex upper Hessenberg matrix H.
Definition: lalg_adv.F90:565
subroutine, public lalg_tridiagonal_function_first_column(n, t, fun, factor, col, factor2, col2)
First column of fun(factor*T) for a real symmetric tridiagonal matrix T.
Definition: lalg_adv.F90:520
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:94
complex(real64) pure function, public phi2(z)
Compute phi2(z) = (phi1(z)-1)/z = (exp(z) - z - 1)/z^2.
Definition: math.F90:996
complex(real64) pure function, public exponential(z)
Wrapper for exponential.
Definition: math.F90:965
complex(real64) pure function, public phi1(z)
Compute phi1(z) = (exp(z)-1)/z.
Definition: math.F90:977
This module defines functions over batches of mesh functions.
Definition: mesh_batch.F90:95
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:155
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.
Definition: mesh.F90:97
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:501
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:138
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:386
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:671
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:570
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:440
/* To use the profiling module, call profiling_in and profiling_out with the label of the region as a...
Definition: profiling.F90:122
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:672
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:604
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
type(type_t), parameter, public type_cmplx
Definition: types.F90:114
Definition: xc.F90:97
Class defining batches of mesh functions.
Definition: batch.F90:142
Class to encapsulate the operator A = S^{-1} H inside the exponential.
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:148
The abstract Hamiltonian class defines a skeleton for specific implementations.
Describes mesh distribution to nodes.
Definition: mesh.F90:165
The states_elec_t class contains all electronic wave functions.
batches of electronic states
Definition: wfs_elec.F90:120
int true(void)