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_mf(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_mf(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_mf(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_mf(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 magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, psib, auxpsib)
356 call batch_axpby(this%mesh%np, this%c2, auxpsib, this%c1, hpsib)
357
358 call auxpsib%end()
359 class default
360 message(1) = "Internal error: imcompatible batch_t in magnus3_linear_operator_apply for argument hpsib."
361 call messages_fatal(1, namespace=this%namespace)
362 end select
363 class default
364 message(1) = "Internal error: imcompatible batch_t in magnus3_linear_operator_apply for argument psib."
365 call messages_fatal(1, namespace=this%namespace)
366 end select
367 end select
368
370 end subroutine magnus3_linear_operator_apply
371
372 ! ---------------------------------------------------------
374 function magnus3_operator_constructor(namespace, mesh, hm1, hm2, hm3, hm4, dt) result(this)
375 type(namespace_t), target, intent(in) :: namespace
376 class(mesh_t), target, intent(in) :: mesh
377 type(hamiltonian_elec_t), target, intent(in) :: hm1
378 type(hamiltonian_elec_t), target, intent(in) :: hm2
379 type(hamiltonian_elec_t), target, intent(in) :: hm3
380 type(hamiltonian_elec_t), target, intent(in) :: hm4
381 real(real64), intent(in) :: dt
382 type(magnus3_operator_t), pointer :: this
383
385
386 allocate(this)
387 call this%init(namespace, mesh, hm1)
388 this%hm1 => hm1
389 this%hm2 => hm2
390 this%hm3 => hm3
391 this%hm4 => hm4
392 this%dt = dt
393
396
397 ! ---------------------------------------------------------
402 subroutine magnus3_operator_apply(this, psib, hpsib)
403 class(magnus3_operator_t), intent(in) :: this
404 class(batch_t), intent(inout) :: psib
405 class(batch_t), intent(inout) :: hpsib
406
407 type(wfs_elec_t) :: k1psib, k2psib, k3psib, k4psib
408 type(wfs_elec_t) :: work1psib, work2psib, sum12psib, commpsib
409
410 push_sub(magnus3_operator_apply)
411
412 select type (hm => this%hm)
413 class is (hamiltonian_elec_t)
414 select type (psib)
415 class is (wfs_elec_t)
416 select type (hpsib)
417 class is (wfs_elec_t)
418 if (hm%d%dim /= 1) call messages_not_implemented("Explicit Magnus 3 with spinors", namespace=this%namespace)
419
420 assert(psib%nst == hpsib%nst)
421
422 call hpsib%copy_to(k1psib, copy_data=.false.)
423 call hpsib%copy_to(k2psib, copy_data=.false.)
424 call hpsib%copy_to(k3psib, copy_data=.false.)
425 call hpsib%copy_to(k4psib, copy_data=.false.)
426 call hpsib%copy_to(work1psib, copy_data=.false.)
427 call hpsib%copy_to(work2psib, copy_data=.false.)
428 call hpsib%copy_to(sum12psib, copy_data=.false.)
429 call hpsib%copy_to(commpsib, copy_data=.false.)
430
431 ! Precompute stage derivatives once:
432 ! k1 = H1 psi, k2 = H2 psi, k3 = H3 psi, k4 = H4 psi.
433 ! no phase treatment needed for first stage
434 call zhamiltonian_elec_apply_batch(this%hm1, this%namespace, this%mesh, psib, k1psib)
435 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, psib, k2psib)
436 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm3, psib, k3psib)
437 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm4, psib, k4psib)
438
439 ! Weighted sum in eq. 22: (k1 + 4 k3 + k4)/6.
440 call k1psib%copy_data_to(this%mesh%np, hpsib)
441 call batch_axpby(this%mesh%np, m_four/6.0_real64, k3psib, m_one/6.0_real64, hpsib)
442 call batch_axpy(this%mesh%np, m_one/6.0_real64, k4psib, hpsib)
443
444 ! Commutator term from eq. 22:
445 ! -1/3 [u3, k3] - 1/12 [u4, k4]
446 ! where u3 = (k1 + k2)/4 and u4 = k2.
447
448 ! [H1 + H2, H3] psi
449 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm1, k3psib, work1psib)
450 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, k3psib, work2psib)
451 call batch_axpy(this%mesh%np, m_one, work2psib, work1psib)
452
453 call k1psib%copy_data_to(this%mesh%np, sum12psib)
454 call batch_axpy(this%mesh%np, m_one, k2psib, sum12psib)
455 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm3, sum12psib, commpsib)
456 call batch_axpy(this%mesh%np, -m_one, commpsib, work1psib)
457
458 ! [H2, H4] psi
459 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm2, k4psib, work2psib)
460 call magnus3_apply_stage_in_ref_phase(this%namespace, this%mesh, this%hm1, this%hm4, k2psib, commpsib)
461 call batch_axpy(this%mesh%np, -m_one, commpsib, work2psib)
462
463 call batch_axpy(this%mesh%np, m_one, work2psib, work1psib)
464 call batch_axpy(this%mesh%np, (m_zi*this%dt)/12.0_real64, work1psib, hpsib)
465
466 call k1psib%end()
467 call k2psib%end()
468 call k3psib%end()
469 call k4psib%end()
470 call work1psib%end()
471 call work2psib%end()
472 call sum12psib%end()
473 call commpsib%end()
474 class default
475 message(1) = "Internal error: imcompatible batch_t in magnus3_operator_apply for argument hpsib."
476 call messages_fatal(1, namespace=this%namespace)
477 end select
478 class default
479 message(1) = "Internal error: imcompatible batch_t in magnus3_operator_apply for argument psib."
480 call messages_fatal(1, namespace=this%namespace)
481 end select
482 end select
483
485 end subroutine magnus3_operator_apply
486
487 ! ---------------------------------------------------------
492 subroutine td_explicit_magnus3(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc)
493 type(v_ks_t), intent(inout) :: ks
494 type(namespace_t), intent(in) :: namespace
495 type(electron_space_t), intent(in) :: space
496 type(hamiltonian_elec_t), target, intent(inout) :: hm
497 type(grid_t), target, intent(inout) :: gr
498 type(states_elec_t), target, intent(inout) :: st
499 type(propagator_base_t), target, intent(inout) :: tr
500 real(real64), intent(in) :: time
501 real(real64), intent(in) :: dt
502 type(ion_dynamics_t), intent(inout) :: ions_dyn
503 type(ions_t), intent(inout) :: ions
504 type(partner_list_t), intent(in) :: ext_partners
505 type(multicomm_t), intent(inout) :: mc
506
507 type(gauge_field_t), pointer :: gfield
508 type(states_elec_t) :: st0, st2, st3, st4
509 type(hamiltonian_elec_t), target :: hm1, hm2, hm3, hm4
510 class(operator_t), pointer :: op
511
512 push_sub(propagator_dt.td_explicit_magnus3)
513
514 ! Stage u1 / k1 (eq. 22):
515 ! Keep Y_n and snapshot H1 = H(t_n, Y_n).
516 call states_elec_copy(st0, st)
517 call hamiltonian_elec_copy(hm1, hm)
518
519 ! Stage u2 = 1/2 k1 -> k2 (eq. 22):
520 ! Predict Y at t_n + dt/2 using H1, then build hm2 from that Y at the midpoint
521 call states_elec_copy(st2, st0)
522 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st2, gr, hm1, m_half*dt)
523
524 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
525 ext_partners, mc, time - m_half*dt, m_half*dt, save_pos = .true.)
526
527 gfield => list_get_gauge_field(ext_partners)
528 if (associated(gfield)) then
529 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, m_half*dt, time, save_gf=.true.)
530 end if
531
532 if (hm%theory_level /= independent_particles) then
533 call v_ks_calc(ks, namespace, space, hm, st2, ions, ext_partners, &
534 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
535 end if
536 call propagation_ops_elec_update_hamiltonian(namespace, space, st2, gr, hm, ext_partners, time - m_half*dt)
537 call hamiltonian_elec_copy(hm2, hm)
538
539 ! Stage u3 = 1/4 (k1 + k2) -> k3 (eq. 22):
540 ! Propagate with 1/4 H1 + 1/4 H2 and build hm3 at the midpoint from st3
541 call states_elec_copy(st3, st0)
542 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_one/4.0_real64, m_one/4.0_real64)
543 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st3, gr, hm1, dt, op=op)
544 safe_deallocate_p(op)
545
546 if (hm%theory_level /= independent_particles) then
547 call v_ks_calc(ks, namespace, space, hm, st3, ions, ext_partners, &
548 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
549 end if
550 call propagation_ops_elec_update_hamiltonian(namespace, space, st3, gr, hm, ext_partners, time - m_half*dt)
551 call hamiltonian_elec_copy(hm3, hm)
552
553 ! Stage u4 = k2 -> k4 (eq. 22):
554 ! Propagate Y_n with H2 to t_n + dt, then rebuild H4 at the end of the step.
555 call states_elec_copy(st4, st0)
556 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st4, gr, hm2, dt)
557
558 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
559 ext_partners, mc, time, m_half*dt)
560 if (associated(gfield)) then
561 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, m_half*dt, time)
562 end if
563
564 if (hm%theory_level /= independent_particles) then
565 call v_ks_calc(ks, namespace, space, hm, st4, ions, ext_partners, &
566 calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
567 end if
568 call propagation_ops_elec_update_hamiltonian(namespace, space, st4, gr, hm, ext_partners, time)
569 call hamiltonian_elec_copy(hm4, hm)
570
571 ! Final stage v3 (eq. 22):
572 ! Combine k1, k3, k4 and the commutator correction
573 ! -1/3 [u3, k3] - 1/12 [u4, k4].
574 op => magnus3_operator_t(namespace, gr, hm1, hm2, hm3, hm4, dt)
575 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm1, dt, op=op)
576 safe_deallocate_p(op)
577
578 ! Restore ions and gauge field to their saved values at t_n.
579 call propagation_ops_elec_restore_ions(tr%propagation_ops_elec, ions_dyn, ions)
580 if (associated(gfield)) then
581 call propagation_ops_elec_restore_gauge_field(tr%propagation_ops_elec, namespace, space, hm, gr, ext_partners)
582 end if
583
584 call states_elec_end(st0)
585 call states_elec_end(st2)
586 call states_elec_end(st3)
588 call hamiltonian_elec_end(hm1)
589 call hamiltonian_elec_end(hm2)
590 call hamiltonian_elec_end(hm3)
591 call hamiltonian_elec_end(hm4)
592
593 pop_sub(propagator_dt.td_explicit_magnus3)
594 end subroutine td_explicit_magnus3
595
596 ! ---------------------------------------------------------
614 subroutine td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter)
615 type(v_ks_t), target, intent(inout) :: ks
616 type(namespace_t), intent(in) :: namespace
617 type(electron_space_t), intent(in) :: space
618 type(hamiltonian_elec_t), target, intent(inout) :: hm
619 type(grid_t), target, intent(inout) :: gr
620 type(states_elec_t), target, intent(inout) :: st
621 type(propagator_base_t), target, intent(inout) :: tr
622 real(real64), intent(in) :: time
623 real(real64), intent(in) :: dt
624 type(ion_dynamics_t), intent(inout) :: ions_dyn
625 type(ions_t), intent(inout) :: ions
626 type(partner_list_t), intent(in) :: ext_partners
627 type(multicomm_t), intent(inout) :: mc
628 integer, intent(in) :: iter
629
630 real(real64) :: alpha1, alpha2, c1, c2, t1, t2, dt1, dt2
631 type(hamiltonian_elec_t), target :: hm1, hm2
632 class(operator_t), pointer :: op
633 type(gauge_field_t), pointer :: gfield
634
635 push_sub(propagator_dt.td_cfmagnus4)
636
637 alpha1 = (m_three - m_two * sqrt(m_three))/12.0_real64
638 alpha2 = (m_three + m_two * sqrt(m_three))/12.0_real64
639 c1 = m_half - sqrt(m_three)/6.0_real64
640 c2 = m_half + sqrt(m_three)/6.0_real64
641 t1 = time - dt + c1*dt
642 t2 = time - dt + c2*dt
643
644 gfield => list_get_gauge_field(ext_partners)
645 dt1 = c1*dt
646 dt2 = (c2 - c1)*dt
647
648 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
649 ext_partners, mc, t1, dt1, save_pos=.true.)
650 if (associated(gfield)) then
651 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, dt1, time, save_gf=.true.)
652 end if
653
654 call hm%ks_pot%interpolate_potentials(tr%vks_old, 4, time, dt, t1)
655 call propagation_ops_elec_update_hamiltonian(namespace, space, st, gr, hm, ext_partners, t1)
656 call hamiltonian_elec_copy(hm1, hm)
657
658 call propagation_ops_elec_move_ions(tr%propagation_ops_elec, gr, hm, st, namespace, space, ions_dyn, ions, &
659 ext_partners, mc, t2, dt2)
660 if (associated(gfield)) then
661 call propagation_ops_elec_propagate_gauge_field(tr%propagation_ops_elec, gfield, dt2, time)
662 end if
663
664 call hm%ks_pot%interpolate_potentials(tr%vks_old, 4, time, dt, t2)
665 call propagation_ops_elec_update_hamiltonian(namespace, space, st, gr, hm, ext_partners, t2)
666 call hamiltonian_elec_copy(hm2, hm)
667
668 call propagation_ops_elec_restore_ions(tr%propagation_ops_elec, ions_dyn, ions)
669 if (associated(gfield)) then
670 call propagation_ops_elec_restore_gauge_field(tr%propagation_ops_elec, namespace, space, hm, gr, ext_partners)
671 end if
672
673 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_two*alpha2, m_two*alpha1)
674 call propagation_ops_elec_exp_apply(tr%te, namespace, st, gr, hm1, m_half*dt, op=op)
675 safe_deallocate_p(op)
676
677 op => magnus3_linear_operator_t(namespace, gr, hm1, hm2, m_two*alpha1, m_two*alpha2)
678 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm1, m_half*dt, op=op)
679 safe_deallocate_p(op)
680
681 call hamiltonian_elec_end(hm1)
682 call hamiltonian_elec_end(hm2)
683
684 pop_sub(propagator_dt.td_cfmagnus4)
685 end subroutine td_cfmagnus4
686
687 ! ---------------------------------------------------------
689 subroutine td_cfmagnus4_sc(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, &
690 iter, sctol, scsteps)
691 type(v_ks_t), intent(inout) :: ks
692 type(namespace_t), intent(in) :: namespace
693 type(electron_space_t), intent(in) :: space
694 type(hamiltonian_elec_t), intent(inout) :: hm
695 type(grid_t), intent(inout) :: gr
696 type(states_elec_t), intent(inout) :: st
697 type(propagator_base_t), intent(inout) :: tr
698 real(real64), intent(in) :: time
699 real(real64), intent(in) :: dt
700 type(ion_dynamics_t), intent(inout) :: ions_dyn
701 type(ions_t), intent(inout) :: ions
702 type(partner_list_t), intent(in) :: ext_partners
703 type(multicomm_t), intent(inout) :: mc
704 integer, intent(in) :: iter
705 real(real64), intent(in) :: sctol
706 integer, optional, intent(out) :: scsteps
707
708 real(real64) :: diff
709 integer :: iter_sc
710 type(states_elec_t) :: st0
711 integer, parameter :: niter = 10
712 type(xc_copied_potentials_t) :: vhxc_pred
713
714 push_sub(propagator_dt.td_cfmagnus4_sc)
715
716 assert(hm%theory_level /= independent_particles)
717
718 call messages_new_line()
719 call messages_write(' Self-consistency iteration:')
720 call messages_info(namespace=namespace)
721
722 ! store copy of initial states
723 call states_elec_copy(st0, st)
724
725 do iter_sc = 1, niter
726 ! Keep a copy of the current end-of-step prediction (history 0)
727 ! to evaluate SC convergence after the propagation.
728 call hm%ks_pot%get_interpolated_potentials(tr%vks_old, 0, storage=vhxc_pred)
729
730 call td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, mc, iter)
731
732 call v_ks_calc(ks, namespace, space, hm, st, ions, ext_partners, &
733 time = time, calc_current = .false., calc_energy = .false., calc_eigenval = .false.)
734 call lda_u_update_occ_matrices(hm%lda_u, namespace, gr, st, hm%phase, hm%energy)
735
736 diff = hm%ks_pot%check_convergence(vhxc_pred, gr, st%rho, st%qtot)
737
738 ! Feed the updated end-of-step potential back into history 0 so
739 ! the next SC iteration interpolates from the latest prediction.
740 call hm%ks_pot%set_interpolated_potentials(tr%vks_old, 0)
741
742 call messages_write(' step ')
743 call messages_write(iter_sc)
744 call messages_write(', residue = ')
745 call messages_write(abs(diff), fmt = '(1x,es9.2)')
746 call messages_info(namespace=namespace)
747
748 if (diff <= sctol) exit
749 if (iter_sc /= niter) then
750 ! restore initial states for next iteration
751 call states_elec_group_copy(st0%d, st0%group, st%group)
752 end if
753 end do
754
755 if (hm%lda_u_level /= dft_u_none) then
756 call lda_u_write_u(hm%lda_u, namespace=namespace)
757 call lda_u_write_v(hm%lda_u, namespace=namespace)
758 end if
759
760 call messages_info(namespace=namespace)
761
762 if (present(scsteps)) scsteps = iter_sc
763
764 call states_elec_end(st0)
765
766 pop_sub(propagator_dt.td_cfmagnus4_sc)
767 end subroutine td_cfmagnus4_sc
768
770
771!! Local Variables:
772!! mode: f90
773!! coding: utf-8
774!! End:
batchified version of the BLAS axpy routine:
Definition: batch_ops.F90:159
batchified multiplication by mesh function with optional conjugation:
Definition: batch_ops.F90:254
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:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_four
Definition: global.F90:204
integer, parameter, public independent_particles
Theory level.
Definition: global.F90:250
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
real(real64), parameter, public m_three
Definition: global.F90:203
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:1049
integer pure elemental function, public laser_kind(laser)
Definition: lasers.F90:719
integer, parameter, public e_field_magnetic
Definition: lasers.F90:179
subroutine, public lda_u_write_u(this, iunit, namespace)
Definition: lda_u_io.F90:528
subroutine, public lda_u_write_v(this, iunit, namespace)
Definition: lda_u_io.F90:576
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:1068
subroutine, public messages_new_line()
Definition: messages.F90:1089
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
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)