Octopus
propagator_magnus.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
23 use batch_oct_m
25 use debug_oct_m
31 use global_oct_m
32 use grid_oct_m
38 use ions_oct_m
39 use, intrinsic :: iso_fortran_env
42 use lda_u_oct_m
43 use lasers_oct_m
45 use mesh_oct_m
48 use parser_oct_m
54 use space_oct_m
57 use v_ks_oct_m
59 use xc_oct_m
60
61 implicit none
62
63 private
64
65 public :: &
66 td_magnus, &
70
71
73 private
74 real(real64), allocatable :: vmagnus(:, :, :)
75 contains
76 procedure :: apply => magnus4_operator_apply
77 end type magnus4_operator_t
78
79 interface magnus4_operator_t
80 procedure magnus4_operator_constructor
81 end interface magnus4_operator_t
82
83
85 private
86 type(hamiltonian_elec_t), pointer :: hm1 => null()
87 type(hamiltonian_elec_t), pointer :: hm2 => null()
88 real(real64) :: c1 = m_zero
89 real(real64) :: c2 = m_zero
90 contains
91 procedure :: apply => magnus3_linear_operator_apply
93
95 procedure magnus3_linear_operator_constructor
96 end interface magnus3_linear_operator_t
97
98
100 private
101 type(hamiltonian_elec_t), pointer :: hm1 => null()
102 type(hamiltonian_elec_t), pointer :: hm2 => null()
103 type(hamiltonian_elec_t), pointer :: hm3 => null()
104 type(hamiltonian_elec_t), pointer :: hm4 => null()
105 real(real64) :: dt = m_zero
106 contains
107 procedure :: apply => magnus3_operator_apply
108 end type magnus3_operator_t
109
110 interface magnus3_operator_t
111 procedure magnus3_operator_constructor
112 end interface magnus3_operator_t
113
114
115contains
117 ! ---------------------------------------------------------
119 subroutine td_magnus(hm, ext_partners, gr, st, tr, namespace, time, dt)
120 type(hamiltonian_elec_t), intent(inout) :: hm
121 type(partner_list_t), intent(in) :: ext_partners
122 type(grid_t), intent(in) :: gr
123 type(states_elec_t), intent(inout) :: st
124 type(propagator_base_t), intent(inout) :: tr
125 type(namespace_t), intent(in) :: namespace
126 real(real64), intent(in) :: time
127 real(real64), intent(in) :: dt
128
129 integer :: j, is, i
130 real(real64) :: atime(2)
131 real(real64), allocatable :: vaux(:, :, :), vmagnus(:, :, :), pot(:)
132 type(lasers_t), pointer :: lasers
133 class(operator_t), pointer :: op
134
135 push_sub(propagator_dt.td_magnus)
136
137 assert(.not. family_is_mgga_with_exc(hm%xc))
138
139 safe_allocate(vaux(1:gr%np, 1:st%d%nspin, 1:2))
140 safe_allocate(vmagnus(1:gr%np, 1:st%d%nspin, 1:2))
141
142 atime(1) = (m_half-sqrt(m_three)/6.0_real64)*dt
143 atime(2) = (m_half+sqrt(m_three)/6.0_real64)*dt
144
145 if (hm%theory_level /= independent_particles) then
146 do j = 1, 2
147 call potential_interpolation_interpolate(tr%vks_old, 3, time, dt, time - dt + atime(j), vaux(:, :, j))
148 end do
149 else
150 vaux = m_zero
151 end if
152
153 do j = 1, 2
154 ! WARNING: This should be carefully tested, and extended to allow for velocity-gauge laser fields.
155 lasers => list_get_lasers(ext_partners)
156 if(associated(lasers)) then
157 do i = 1, lasers%no_lasers
158 select case (laser_kind(lasers%lasers(i)))
159 case (e_field_electric)
160 safe_allocate(pot(1:gr%np))
161 pot = m_zero
162 call laser_potential(lasers%lasers(i), gr, pot, time - dt + atime(j))
163 do is = 1, st%d%nspin
164 vaux(:, is, j) = vaux(:, is, j) + pot(:)
165 end do
166 safe_deallocate_a(pot)
168 write(message(1),'(a)') 'The Magnus propagator cannot be used with magnetic fields, or'
169 write(message(2),'(a)') 'with an electric field described in the velocity gauge.'
170 call messages_fatal(2, namespace=namespace)
171 end select
172 end do
173 end if
174 end do
175
176 vmagnus(:, :, 2) = m_half*(vaux(:, :, 1) + vaux(:, :, 2))
177 vmagnus(:, :, 1) = (sqrt(m_three)/12.0_real64)*dt*(vaux(:, :, 2) - vaux(:, :, 1))
178
179 op => magnus4_operator_t(namespace, gr, hm, vmagnus)
180 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm, dt, op=op)
181 safe_deallocate_p(op)
183 safe_deallocate_a(vaux)
184 safe_deallocate_a(vmagnus)
185 pop_sub(propagator_dt.td_magnus)
186 end subroutine td_magnus
187
188 function magnus4_operator_constructor(namespace, mesh, hm, vmagnus) result(this)
189 type(namespace_t), target, intent(in) :: namespace
190 class(mesh_t), target, intent(in) :: mesh
191 class(hamiltonian_abst_t), target, intent(in) :: hm
192 real(real64), intent(in) :: vmagnus(:, :, :)
193 type(magnus4_operator_t), pointer :: this
197 allocate(this)
198 call this%init(namespace, mesh, hm)
200 select type(hm)
201 class is (hamiltonian_elec_t)
202 assert(size(vmagnus, 1) >= mesh%np)
203 assert(size(vmagnus, 2) == hm%d%nspin)
204 assert(size(vmagnus, 3) == 2)
205 class default
206 write(message(1), '(a)') 'Magnus operators only implemented for electrons at the moment'
207 call messages_fatal(1, namespace=namespace)
208 end select
209 safe_allocate_source(this%vmagnus, vmagnus)
210
213
214 subroutine magnus4_operator_apply(this, psib, hpsib)
215 class(magnus4_operator_t), intent(in) :: this
216 class(batch_t), intent(inout) :: psib
217 class(batch_t), intent(inout) :: hpsib
218
219 integer :: ispin
220 type(wfs_elec_t) :: auxpsib, aux2psib
221
222 push_sub(magnus4_operator_apply)
223
224 select type(hm => this%hm)
225 class is (hamiltonian_elec_t)
226 select type (psib)
227 class is (wfs_elec_t)
228 select type (hpsib)
229 class is (wfs_elec_t)
230 ! We will assume, for the moment, no spinors.
231 if (hm%d%dim /= 1) call messages_not_implemented("Magnus with spinors", namespace=this%namespace)
232
233 assert(psib%nst == hpsib%nst)
234
235 ispin = hm%d%get_spin_index(psib%ik)
236
237 call hpsib%copy_to(auxpsib, copy_data=.false.)
238 call hpsib%copy_to(aux2psib, copy_data=.false.)
239
240 ! Compute (T + Vnl)|psi> and store it
241 call zhamiltonian_elec_apply_batch(hm, this%namespace, this%mesh, psib, auxpsib, &
243
244 ! H|psi> = (T + Vnl)|psi> + Vpsl|psi> + Vmagnus(t2)|psi> + Vborders|psi>
245 call auxpsib%copy_data_to(this%mesh%np, hpsib)
246 call zhamiltonian_elec_external(hm, this%mesh, psib, hpsib)
247 if (hm%abs_boundaries%abtype == imaginary_absorbing) then
248 call batch_mul(this%mesh%np, hm%abs_boundaries%mf(1:this%mesh%np), psib, aux2psib)
249 call batch_axpy(this%mesh%np, m_zi, aux2psib, hpsib)
250 end if
251 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 2), psib, aux2psib)
252 call batch_axpy(this%mesh%np, m_one, aux2psib, hpsib)
253
254 ! Add first term of the commutator: - i Vmagnus(t1) (T + Vnl) |psi>
255 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 1), auxpsib, aux2psib)
256 call batch_axpy(this%mesh%np, -m_zi, aux2psib, hpsib)
257
258 ! Add second term of commutator: i (T + Vnl) Vmagnus(t1) |psi>
259 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 1), psib, auxpsib)
260 call zhamiltonian_elec_apply_batch(hm, this%namespace, this%mesh, auxpsib, aux2psib, &
262 call batch_axpy(this%mesh%np, m_zi, aux2psib, hpsib)
263
264 call auxpsib%end()
265 call aux2psib%end()
266 class default
267 message(1) = "Internal error: imcompatible batch_t in magnus4_operator_apply for argument hpsib."
268 call messages_fatal(1, namespace=this%namespace)
269 end select
270 class default
271 message(1) = "Internal error: imcompatible batch_t in magnus4_operator_apply for argument psib."
272 call messages_fatal(1, namespace=this%namespace)
273 end select
274 end select
275
277 end subroutine magnus4_operator_apply
278
279 ! ---------------------------------------------------------
281 function magnus3_linear_operator_constructor(namespace, mesh, hm1, hm2, c1, c2) result(this)
282 type(namespace_t), target, intent(in) :: namespace
283 class(mesh_t), target, intent(in) :: mesh
284 type(hamiltonian_elec_t), target, intent(in) :: hm1
285 type(hamiltonian_elec_t), target, intent(in) :: hm2
286 real(real64), intent(in) :: c1
287 real(real64), intent(in) :: c2
288 type(magnus3_linear_operator_t), pointer :: this
289
291
292 allocate(this)
293 call this%init(namespace, mesh, hm1)
294 this%hm1 => hm1
295 this%hm2 => hm2
296 this%c1 = c1
297 this%c2 = c2
298
301
302 ! ---------------------------------------------------------
304 subroutine magnus3_apply_stage_in_ref_phase(namespace, mesh, hm_ref, hm_stage, psib, hpsib)
305 type(namespace_t), intent(in) :: namespace
306 class(mesh_t), intent(in) :: mesh
307 type(hamiltonian_elec_t), intent(in) :: hm_ref
308 type(hamiltonian_elec_t), intent(in) :: hm_stage
309 type(wfs_elec_t), intent(inout) :: psib
310 type(wfs_elec_t), intent(inout) :: hpsib
311
313
314 if (hm_ref%phase%is_allocated()) call hm_ref%phase%unset_phase_corr(mesh, psib)
315 if (hm_stage%phase%is_allocated()) call hm_stage%phase%set_phase_corr(mesh, psib)
316
317 call zhamiltonian_elec_apply_batch(hm_stage, namespace, mesh, psib, hpsib)
318
319 if (hm_stage%phase%is_allocated()) then
320 call hm_stage%phase%unset_phase_corr(mesh, hpsib)
321 call hm_stage%phase%unset_phase_corr(mesh, psib)
322 end if
323 if (hm_ref%phase%is_allocated()) then
324 call hm_ref%phase%set_phase_corr(mesh, hpsib)
325 call hm_ref%phase%set_phase_corr(mesh, psib)
326 end if
327
330
331 ! ---------------------------------------------------------
333 subroutine magnus3_linear_operator_apply(this, psib, hpsib)
334 class(magnus3_linear_operator_t), intent(in) :: this
335 class(batch_t), intent(inout) :: psib
336 class(batch_t), intent(inout) :: hpsib
337
338 type(wfs_elec_t) :: auxpsib
339
341
342 select type (hm => this%hm)
343 class is (hamiltonian_elec_t)
344 select type (psib)
345 class is (wfs_elec_t)
346 select type (hpsib)
347 class is (wfs_elec_t)
348 if (hm%d%dim /= 1) call messages_not_implemented("Explicit Magnus 3 with spinors", namespace=this%namespace)
349
350 assert(psib%nst == hpsib%nst)
351
352 call hpsib%copy_to(auxpsib, copy_data=.false.)
353
354 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm1, psib, hpsib)
355 call batch_scal(this%mesh%np, this%c1, hpsib)
356
357 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, psib, auxpsib)
358 call batch_axpy(this%mesh%np, this%c2, auxpsib, hpsib)
359
360 call auxpsib%end()
361 class default
362 message(1) = "Internal error: imcompatible batch_t in magnus3_linear_operator_apply for argument hpsib."
363 call messages_fatal(1, namespace=this%namespace)
364 end select
365 class default
366 message(1) = "Internal error: imcompatible batch_t in magnus3_linear_operator_apply for argument psib."
367 call messages_fatal(1, namespace=this%namespace)
368 end select
369 end select
370
372 end subroutine magnus3_linear_operator_apply
373
374 ! ---------------------------------------------------------
376 function magnus3_operator_constructor(namespace, mesh, hm1, hm2, hm3, hm4, dt) result(this)
377 type(namespace_t), target, intent(in) :: namespace
378 class(mesh_t), target, intent(in) :: mesh
379 type(hamiltonian_elec_t), target, intent(in) :: hm1
380 type(hamiltonian_elec_t), target, intent(in) :: hm2
381 type(hamiltonian_elec_t), target, intent(in) :: hm3
382 type(hamiltonian_elec_t), target, intent(in) :: hm4
383 real(real64), intent(in) :: dt
384 type(magnus3_operator_t), pointer :: this
385
387
388 allocate(this)
389 call this%init(namespace, mesh, hm1)
390 this%hm1 => hm1
391 this%hm2 => hm2
392 this%hm3 => hm3
393 this%hm4 => hm4
394 this%dt = dt
395
398
399 ! ---------------------------------------------------------
404 subroutine magnus3_operator_apply(this, psib, hpsib)
405 class(magnus3_operator_t), intent(in) :: this
406 class(batch_t), intent(inout) :: psib
407 class(batch_t), intent(inout) :: hpsib
408
409 type(wfs_elec_t) :: k1psib, k2psib, k3psib, k4psib
410 type(wfs_elec_t) :: work1psib, work2psib, sum12psib, commpsib
411
412 push_sub(magnus3_operator_apply)
413
414 select type (hm => this%hm)
415 class is (hamiltonian_elec_t)
416 select type (psib)
417 class is (wfs_elec_t)
418 select type (hpsib)
419 class is (wfs_elec_t)
420 if (hm%d%dim /= 1) call messages_not_implemented("Explicit Magnus 3 with spinors", namespace=this%namespace)
421
422 assert(psib%nst == hpsib%nst)
423
424 call hpsib%copy_to(k1psib, copy_data=.false.)
425 call hpsib%copy_to(k2psib, copy_data=.false.)
426 call hpsib%copy_to(k3psib, copy_data=.false.)
427 call hpsib%copy_to(k4psib, copy_data=.false.)
428 call hpsib%copy_to(work1psib, copy_data=.false.)
429 call hpsib%copy_to(work2psib, copy_data=.false.)
430 call hpsib%copy_to(sum12psib, copy_data=.false.)
431 call hpsib%copy_to(commpsib, copy_data=.false.)
432
433 ! Precompute stage derivatives once:
434 ! k1 = H1 psi, k2 = H2 psi, k3 = H3 psi, k4 = H4 psi.
435 ! no phase treatment needed for first stage
436 call zhamiltonian_elec_apply_batch(this%hm1, this%namespace, this%mesh, psib, k1psib)
437 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, psib, k2psib)
438 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm3, psib, k3psib)
439 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm4, psib, k4psib)
440
441 ! Weighted sum in eq. 22: (k1 + 4 k3 + k4)/6.
442 call k1psib%copy_data_to(this%mesh%np, hpsib)
443 call batch_scal(this%mesh%np, m_one/6.0_real64, hpsib)
444 call batch_axpy(this%mesh%np, m_four/6.0_real64, k3psib, hpsib)
445 call batch_axpy(this%mesh%np, m_one/6.0_real64, k4psib, hpsib)
446
447 ! Commutator term from eq. 22:
448 ! -1/3 [u3, k3] - 1/12 [u4, k4]
449 ! where u3 = (k1 + k2)/4 and u4 = k2.
450
451 ! [H1 + H2, H3] psi
452 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm1, k3psib, work1psib)
453 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, k3psib, work2psib)
454 call batch_axpy(this%mesh%np, m_one, work2psib, work1psib)
455
456 call k1psib%copy_data_to(this%mesh%np, sum12psib)
457 call batch_axpy(this%mesh%np, m_one, k2psib, sum12psib)
458 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm3, sum12psib, commpsib)
459 call batch_axpy(this%mesh%np, -m_one, commpsib, work1psib)
460
461 ! [H2, H4] psi
462 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, k4psib, work2psib)
463 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm4, k2psib, commpsib)
464 call batch_axpy(this%mesh%np, -m_one, commpsib, work2psib)
465
466 call batch_axpy(this%mesh%np, m_one, work2psib, work1psib)
467 call batch_axpy(this%mesh%np, (m_zi*this%dt)/12.0_real64, work1psib, hpsib)
468
469 call k1psib%end()
470 call k2psib%end()
471 call k3psib%end()
472 call k4psib%end()
473 call work1psib%end()
474 call work2psib%end()
475 call sum12psib%end()
476 call commpsib%end()
477 class default
478 message(1) = "Internal error: imcompatible batch_t in magnus3_operator_apply for argument hpsib."
479 call messages_fatal(1, namespace=this%namespace)
480 end select
481 class default
482 message(1) = "Internal error: imcompatible batch_t in magnus3_operator_apply for argument psib."
483 call messages_fatal(1, namespace=this%namespace)
484 end select
485 end select
486
488 end subroutine magnus3_operator_apply
489
490 ! ---------------------------------------------------------
495 subroutine td_explicit_magnus3(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc)
496 type(v_ks_t), intent(inout) :: ks
497 type(namespace_t), intent(in) :: namespace
498 type(electron_space_t), intent(in) :: space
499 type(hamiltonian_elec_t), target, intent(inout) :: hm
500 type(grid_t), target, intent(inout) :: gr
501 type(states_elec_t), target, intent(inout) :: st
502 type(propagator_base_t), target, intent(inout) :: tr
503 real(real64), intent(in) :: time
504 real(real64), intent(in) :: dt
505 type(ion_dynamics_t), intent(inout) :: ions_dyn
506 type(ions_t), intent(inout) :: ions
507 type(partner_list_t), intent(in) :: ext_partners
508 type(multicomm_t), intent(inout) :: mc
509
510 type(gauge_field_t), pointer :: gfield
511 type(states_elec_t) :: st0, st2, st3, st4
512 type(hamiltonian_elec_t), target :: hm1, hm2, hm3, hm4
513 class(operator_t), pointer :: op
514
515 push_sub(propagator_dt.td_explicit_magnus3)
516
517 ! Stage u1 / k1 (eq. 22):
518 ! Keep Y_n and snapshot H1 = H(t_n, Y_n).
519 call states_elec_copy(st0, st)
520 call hamiltonian_elec_copy(hm1, hm)
521
522 ! Stage u2 = 1/2 k1 -> k2 (eq. 22):
523 ! Predict Y at t_n + dt/2 using H1, then build hm2 from that Y at the midpoint
524 call states_elec_copy(st2, st0)
525 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st2, gr, hm1, m_half*dt)
526
527 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
528 ext_partners, mc, time - m_half*dt, m_half*dt, save_pos = .true.)
529
530 gfield => list_get_gauge_field(ext_partners)
531 if (associated(gfield)) then
532 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, m_half*dt, time, save_gf=.true.)
533 end if
534
535 if (hm%theory_level /= independent_particles) then
536 call v_ks_calc(ks, namespace, space, hm, st2, ions, ext_partners, &
537 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
538 end if
539 call propagation_ops_elec_update_hamiltonian(namespace, space, st2, gr, hm, ext_partners, time - m_half*dt)
540 call hamiltonian_elec_copy(hm2, hm)
541
542 ! Stage u3 = 1/4 (k1 + k2) -> k3 (eq. 22):
543 ! Propagate with 1/4 H1 + 1/4 H2 and build hm3 at the midpoint from st3
544 call states_elec_copy(st3, st0)
545 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_one/4.0_real64, m_one/4.0_real64)
546 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st3, gr, hm1, dt, op=op)
547 safe_deallocate_p(op)
548
549 if (hm%theory_level /= independent_particles) then
550 call v_ks_calc(ks, namespace, space, hm, st3, ions, ext_partners, &
551 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
552 end if
553 call propagation_ops_elec_update_hamiltonian(namespace, space, st3, gr, hm, ext_partners, time - m_half*dt)
554 call hamiltonian_elec_copy(hm3, hm)
555
556 ! Stage u4 = k2 -> k4 (eq. 22):
557 ! Propagate Y_n with H2 to t_n + dt, then rebuild H4 at the end of the step.
558 call states_elec_copy(st4, st0)
559 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st4, gr, hm2, dt)
560
561 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
562 ext_partners, mc, time, m_half*dt)
563 if (associated(gfield)) then
564 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, m_half*dt, time)
565 end if
566
567 if (hm%theory_level /= independent_particles) then
568 call v_ks_calc(ks, namespace, space, hm, st4, ions, ext_partners, &
569 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
570 end if
571 call propagation_ops_elec_update_hamiltonian(namespace, space, st4, gr, hm, ext_partners, time)
572 call hamiltonian_elec_copy(hm4, hm)
573
574 ! Final stage v3 (eq. 22):
575 ! Combine k1, k3, k4 and the commutator correction
576 ! -1/3 [u3, k3] - 1/12 [u4, k4].
577 op => magnus3_operator_t(namespace, gr, hm1, hm2, hm3, hm4, dt)
578 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm1, dt, op=op)
579 safe_deallocate_p(op)
580
581 ! Restore ions and gauge field to their saved values at t_n.
582 call propagation_ops_elec_restore_ions(tr%propagation_ops_elec, ions_dyn, ions)
583 if (associated(gfield)) then
584 call propagation_ops_elec_restore_gauge_field(tr%propagation_ops_elec, namespace, space, hm, gr, ext_partners)
585 end if
586
587 call states_elec_end(st0)
588 call states_elec_end(st2)
589 call states_elec_end(st3)
591 call hamiltonian_elec_end(hm1)
592 call hamiltonian_elec_end(hm2)
593 call hamiltonian_elec_end(hm3)
594 call hamiltonian_elec_end(hm4)
595
596 pop_sub(propagator_dt.td_explicit_magnus3)
597 end subroutine td_explicit_magnus3
598
599 ! ---------------------------------------------------------
617 subroutine td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter)
618 type(v_ks_t), target, intent(inout) :: ks
619 type(namespace_t), intent(in) :: namespace
620 type(electron_space_t), intent(in) :: space
621 type(hamiltonian_elec_t), target, intent(inout) :: hm
622 type(grid_t), target, intent(inout) :: gr
623 type(states_elec_t), target, intent(inout) :: st
624 type(propagator_base_t), target, intent(inout) :: tr
625 real(real64), intent(in) :: time
626 real(real64), intent(in) :: dt
627 type(ion_dynamics_t), intent(inout) :: ions_dyn
628 type(ions_t), intent(inout) :: ions
629 type(partner_list_t), intent(in) :: ext_partners
630 type(multicomm_t), intent(inout) :: mc
631 integer, intent(in) :: iter
632
633 real(real64) :: alpha1, alpha2, c1, c2, t1, t2, dt1, dt2
634 type(hamiltonian_elec_t), target :: hm1, hm2
635 class(operator_t), pointer :: op
636 type(gauge_field_t), pointer :: gfield
637
638 push_sub(propagator_dt.td_cfmagnus4)
639
640 alpha1 = (m_three - m_two * sqrt(m_three))/12.0_real64
641 alpha2 = (m_three + m_two * sqrt(m_three))/12.0_real64
642 c1 = m_half - sqrt(m_three)/6.0_real64
643 c2 = m_half + sqrt(m_three)/6.0_real64
644 t1 = time - dt + c1*dt
645 t2 = time - dt + c2*dt
646
647 gfield => list_get_gauge_field(ext_partners)
648 dt1 = c1*dt
649 dt2 = (c2 - c1)*dt
650
651 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
652 ext_partners, mc, t1, dt1, save_pos=.true.)
653 if (associated(gfield)) then
654 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, dt1, time, save_gf=.true.)
655 end if
656
657 call hm%ks_pot%interpolate_potentials(tr%vks_old, 4, time, dt, t1)
658 call propagation_ops_elec_update_hamiltonian(namespace, space, st, gr, hm, ext_partners, t1)
659 call hamiltonian_elec_copy(hm1, hm)
660
661 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
662 ext_partners, mc, t2, dt2)
663 if (associated(gfield)) then
664 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, dt2, time)
665 end if
666
667 call hm%ks_pot%interpolate_potentials(tr%vks_old, 4, time, dt, t2)
668 call propagation_ops_elec_update_hamiltonian(namespace, space, st, gr, hm, ext_partners, t2)
669 call hamiltonian_elec_copy(hm2, hm)
670
671 call propagation_ops_elec_restore_ions(tr%propagation_ops_elec, ions_dyn, ions)
672 if (associated(gfield)) then
673 call propagation_ops_elec_restore_gauge_field(tr%propagation_ops_elec, namespace, space, hm, gr, ext_partners)
674 end if
675
676 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_two*alpha2, m_two*alpha1)
677 call propagation_ops_elec_exp_apply(tr%te, namespace, st, gr, hm1, m_half*dt, op=op)
678 safe_deallocate_p(op)
679
680 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_two*alpha1, m_two*alpha2)
681 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm1, m_half*dt, op=op)
682 safe_deallocate_p(op)
683
684 call hamiltonian_elec_end(hm1)
685 call hamiltonian_elec_end(hm2)
686
687 pop_sub(propagator_dt.td_cfmagnus4)
688 end subroutine td_cfmagnus4
689
690 ! ---------------------------------------------------------
692 subroutine td_cfmagnus4_sc(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, &
693 iter, sctol, scsteps)
694 type(v_ks_t), intent(inout) :: ks
695 type(namespace_t), intent(in) :: namespace
696 type(electron_space_t), intent(in) :: space
697 type(hamiltonian_elec_t), intent(inout) :: hm
698 type(grid_t), intent(inout) :: gr
699 type(states_elec_t), intent(inout) :: st
700 type(propagator_base_t), intent(inout) :: tr
701 real(real64), intent(in) :: time
702 real(real64), intent(in) :: dt
703 type(ion_dynamics_t), intent(inout) :: ions_dyn
704 type(ions_t), intent(inout) :: ions
705 type(partner_list_t), intent(in) :: ext_partners
706 type(multicomm_t), intent(inout) :: mc
707 integer, intent(in) :: iter
708 real(real64), intent(in) :: sctol
709 integer, optional, intent(out) :: scsteps
710
711 real(real64) :: diff
712 integer :: iter_sc
713 type(states_elec_t) :: st0
714 integer, parameter :: niter = 10
715 type(xc_copied_potentials_t) :: vhxc_pred
716
717 push_sub(propagator_dt.td_cfmagnus4_sc)
718
719 assert(hm%theory_level /= independent_particles)
720
721 call messages_new_line()
722 call messages_write(' Self-consistency iteration:')
723 call messages_info(namespace=namespace)
724
725 ! store copy of initial states
726 call states_elec_copy(st0, st)
727
728 do iter_sc = 1, niter
729 ! Keep a copy of the current end-of-step prediction (history 0)
730 ! to evaluate SC convergence after the propagation.
731 call hm%ks_pot%get_interpolated_potentials(tr%vks_old, 0, storage=vhxc_pred)
732
733 call td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter)
734
735 call v_ks_calc(ks, namespace, space, hm, st, ions, ext_partners, &
736 time = time, calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
737 call lda_u_update_occ_matrices(hm%lda_u, namespace, gr, st, hm%phase, hm%energy)
738
739 diff = hm%ks_pot%check_convergence(vhxc_pred, gr, st%rho, st%qtot)
740
741 ! Feed the updated end-of-step potential back into history 0 so
742 ! the next SC iteration interpolates from the latest prediction.
743 call hm%ks_pot%set_interpolated_potentials(tr%vks_old, 0)
744
745 call messages_write(' step ')
746 call messages_write(iter_sc)
747 call messages_write(', residue = ')
748 call messages_write(abs(diff), fmt = '(1x,es9.2)')
749 call messages_info(namespace=namespace)
750
751 if (diff <= sctol) exit
752 if (iter_sc /= niter) then
753 ! restore initial states for next iteration
754 call states_elec_group_copy(st0%d, st0%group, st%group)
755 end if
756 end do
757
758 if (hm%lda_u_level /= dft_u_none) then
759 call lda_u_write_u(hm%lda_u, namespace=namespace)
760 call lda_u_write_v(hm%lda_u, namespace=namespace)
761 end if
762
763 call messages_info(namespace=namespace)
764
765 if (present(scsteps)) scsteps = iter_sc
766
767 call states_elec_end(st0)
768
769 pop_sub(propagator_dt.td_cfmagnus4_sc)
770 end subroutine td_cfmagnus4_sc
771
773
774!! Local Variables:
775!! mode: f90
776!! coding: utf-8
777!! End:
batchified version of the BLAS axpy routine:
Definition: batch_ops.F90:156
scale a batch by a constant or vector
Definition: batch_ops.F90:164
double sqrt(double __x) __attribute__((__nothrow__
integer, parameter, public imaginary_absorbing
This module implements batches of mesh functions.
Definition: batch.F90:135
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:118
This module implements a calculator for the density and defines related functions.
Definition: density.F90:122
type(gauge_field_t) function, pointer, public list_get_gauge_field(partners)
type(lasers_t) function, pointer, public list_get_lasers(partners)
real(real64), parameter, public m_two
Definition: global.F90:193
real(real64), parameter, public m_zero
Definition: global.F90:191
real(real64), parameter, public m_four
Definition: global.F90:195
integer, parameter, public independent_particles
Theory level.
Definition: global.F90:241
complex(real64), parameter, public m_zi
Definition: global.F90:205
real(real64), parameter, public m_half
Definition: global.F90:197
real(real64), parameter, public m_one
Definition: global.F90:192
real(real64), parameter, public m_three
Definition: global.F90:194
This module implements the underlying real-space grid.
Definition: grid.F90:119
This module defines an abstract class for Hamiltonians.
integer, parameter, public term_non_local_potential
integer, parameter, public term_kinetic
subroutine, public zhamiltonian_elec_apply_batch(hm, namespace, mesh, psib, hpsib, terms, set_bc)
subroutine, public hamiltonian_elec_end(hm)
subroutine, public hamiltonian_elec_copy(hm_out, hm_in)
Deep-copy a hamiltonian_elec_t snapshot.
subroutine, public zhamiltonian_elec_external(this, mesh, psib, vpsib)
This module defines classes and functions for interaction partners.
A module to handle KS potential, without the external potential.
integer, parameter, public e_field_electric
Definition: lasers.F90:179
integer, parameter, public e_field_vector_potential
Definition: lasers.F90:179
subroutine, public laser_potential(laser, mesh, pot, time)
Definition: lasers.F90:1045
integer pure elemental function, public laser_kind(laser)
Definition: lasers.F90:717
integer, parameter, public e_field_magnetic
Definition: lasers.F90:179
subroutine, public lda_u_write_u(this, iunit, namespace)
Definition: lda_u_io.F90:533
subroutine, public lda_u_write_v(this, iunit, namespace)
Definition: lda_u_io.F90:582
integer, parameter, public dft_u_none
Definition: lda_u.F90:205
subroutine, public lda_u_update_occ_matrices(this, namespace, mesh, st, phase, energy)
Definition: lda_u.F90:892
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1067
subroutine, public messages_new_line()
Definition: messages.F90:1088
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:161
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:409
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:593
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
subroutine, public potential_interpolation_interpolate(potential_interpolation, order, time, dt, t, vhxc, vtau)
subroutine, public propagation_ops_elec_restore_ions(wo, ions_dyn, ions)
subroutine, public propagation_ops_elec_propagate_gauge_field(wo, gfield, dt, time, save_gf)
subroutine, public propagation_ops_elec_update_hamiltonian(namespace, space, st, mesh, hm, ext_partners, time)
subroutine, public propagation_ops_elec_fuse_density_exp_apply(te, namespace, st, gr, hm, dt, dt2, op)
subroutine, public propagation_ops_elec_restore_gauge_field(wo, namespace, space, hm, mesh, ext_partners)
subroutine, public propagation_ops_elec_move_ions(wo, gr, hm, st, namespace, space, ions_dyn, ions, ext_partners, mc, time, dt, save_pos)
subroutine, public propagation_ops_elec_exp_apply(te, namespace, st, mesh, hm, dt, op)
type(magnus3_linear_operator_t) function, pointer magnus3_linear_operator_constructor(namespace, mesh, hm1, hm2, c1, c2)
Build a linear Hamiltonian operator c1*H1 + c2*H2.
subroutine magnus4_operator_apply(this, psib, hpsib)
subroutine magnus3_operator_apply(this, psib, hpsib)
Apply the explicit Magnus-3 operator (weighted stage sum plus commutator term). The equation refers t...
subroutine magnus3_linear_operator_apply(this, psib, hpsib)
Apply the linear Hamiltonian operator for the explicit Magnus-3 stages.
subroutine, public td_magnus(hm, ext_partners, gr, st, tr, namespace, time, dt)
Magnus propagator.
type(magnus4_operator_t) function, pointer magnus4_operator_constructor(namespace, mesh, hm, vmagnus)
subroutine, public td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter)
Commutator-free Magnus propagator of order 4. This method has been developed for linear systems and i...
subroutine, public td_explicit_magnus3(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc)
Third-order explicit Magnus propagator. This implements equation (22) from Casas, F....
type(magnus3_operator_t) function, pointer magnus3_operator_constructor(namespace, mesh, hm1, hm2, hm3, hm4, dt)
Build the explicit Magnus-3 final-stage operator from stage Hamiltonians.
subroutine, public td_cfmagnus4_sc(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter, sctol, scsteps)
Commutator-free Magnus propagator of order 4 with self-consistency.
subroutine magnus3_apply_stage_in_ref_phase(namespace, mesh, hm_ref, hm_stage, psib, hpsib)
Apply a stage Hamiltonian in the reference Hamiltonian phase convention.
This module handles groups of electronic batches and their parallel distribution.
subroutine, public states_elec_group_copy(d, group_in, group_out, copy_data, special)
make a copy of a group
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
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:754
Definition: xc.F90:116
logical pure function, public family_is_mgga_with_exc(xcs)
Is the xc function part of the mGGA family with an energy functional.
Definition: xc.F90:599
Class defining batches of mesh functions.
Definition: batch.F90:161
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:171
The abstract Hamiltonian class defines a skeleton for specific implementations.
Describes mesh distribution to nodes.
Definition: mesh.F90:187
Stores all communicators and groups.
Definition: multicomm.F90:208
Class to encapsulate the operation for the explicit Magnus 3 propagator.
Class to encapsulate linear combinations of two Hamiltonians.
The states_elec_t class contains all electronic wave functions.
batches of electronic states
Definition: wfs_elec.F90:141
int true(void)