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
41 use lasers_oct_m
43 use mesh_oct_m
45 use parser_oct_m
51 use space_oct_m
53 use v_ks_oct_m
55 use xc_oct_m
56
57 implicit none
58
59 private
60
61 public :: &
62 td_magnus, &
64
65
67 private
68 real(real64), allocatable :: vmagnus(:, :, :)
69 contains
70 procedure :: apply => magnus4_operator_apply
71 end type magnus4_operator_t
72
73 interface magnus4_operator_t
74 procedure magnus4_operator_constructor
75 end interface magnus4_operator_t
76
77
78contains
79
80 ! ---------------------------------------------------------
82 subroutine td_magnus(hm, ext_partners, gr, st, tr, namespace, time, dt)
83 type(hamiltonian_elec_t), intent(inout) :: hm
84 type(partner_list_t), intent(in) :: ext_partners
85 type(grid_t), intent(in) :: gr
86 type(states_elec_t), intent(inout) :: st
87 type(propagator_base_t), intent(inout) :: tr
88 type(namespace_t), intent(in) :: namespace
89 real(real64), intent(in) :: time
90 real(real64), intent(in) :: dt
91
92 integer :: j, is, i
93 real(real64) :: atime(2)
94 real(real64), allocatable :: vaux(:, :, :), vmagnus(:, :, :), pot(:)
95 type(lasers_t), pointer :: lasers
96 class(operator_t), pointer :: op
97
98 push_sub(propagator_dt.td_magnus)
99
100 assert(.not. family_is_mgga_with_exc(hm%xc))
101
102 safe_allocate(vaux(1:gr%np, 1:st%d%nspin, 1:2))
103 safe_allocate(vmagnus(1:gr%np, 1:st%d%nspin, 1:2))
104
105 atime(1) = (m_half-sqrt(m_three)/6.0_real64)*dt
106 atime(2) = (m_half+sqrt(m_three)/6.0_real64)*dt
107
108 if (hm%theory_level /= independent_particles) then
109 do j = 1, 2
110 call potential_interpolation_interpolate(tr%vks_old, 3, time, dt, time - dt + atime(j), vaux(:, :, j))
111 end do
112 else
113 vaux = m_zero
114 end if
115
116 do j = 1, 2
117 ! WARNING: This should be carefully tested, and extended to allow for velocity-gauge laser fields.
118 lasers => list_get_lasers(ext_partners)
119 if(associated(lasers)) then
120 do i = 1, lasers%no_lasers
121 select case (laser_kind(lasers%lasers(i)))
122 case (e_field_electric)
123 safe_allocate(pot(1:gr%np))
124 pot = m_zero
125 call laser_potential(lasers%lasers(i), gr, pot, time - dt + atime(j))
126 do is = 1, st%d%nspin
127 vaux(:, is, j) = vaux(:, is, j) + pot(:)
128 end do
129 safe_deallocate_a(pot)
131 write(message(1),'(a)') 'The Magnus propagator cannot be used with magnetic fields, or'
132 write(message(2),'(a)') 'with an electric field described in the velocity gauge.'
133 call messages_fatal(2, namespace=namespace)
134 end select
135 end do
136 end if
137 end do
138
139 vmagnus(:, :, 2) = m_half*(vaux(:, :, 1) + vaux(:, :, 2))
140 vmagnus(:, :, 1) = (sqrt(m_three)/12.0_real64)*dt*(vaux(:, :, 2) - vaux(:, :, 1))
141
142 op => magnus4_operator_t(namespace, gr, hm, vmagnus)
143 call propagation_ops_elec_fuse_density_exp_apply(tr%te, namespace, st, gr, hm, dt, op=op)
144 safe_deallocate_p(op)
145
146 safe_deallocate_a(vaux)
147 safe_deallocate_a(vmagnus)
148 pop_sub(propagator_dt.td_magnus)
149 end subroutine td_magnus
150
151 function magnus4_operator_constructor(namespace, mesh, hm, vmagnus) result(this)
152 type(namespace_t), target, intent(in) :: namespace
153 class(mesh_t), target, intent(in) :: mesh
154 class(hamiltonian_abst_t), target, intent(in) :: hm
155 real(real64), intent(in) :: vmagnus(:, :, :)
156 type(magnus4_operator_t), pointer :: this
157
159
160 allocate(this)
161 call this%init(namespace, mesh, hm)
162
163 select type(hm)
164 class is (hamiltonian_elec_t)
165 assert(size(vmagnus, 1) >= mesh%np)
166 assert(size(vmagnus, 2) == hm%d%nspin)
167 assert(size(vmagnus, 3) == 2)
168 class default
169 write(message(1), '(a)') 'Magnus operators only implemented for electrons at the moment'
170 call messages_fatal(1, namespace=namespace)
171 end select
172 safe_allocate_source(this%vmagnus, vmagnus)
173
176
177 subroutine magnus4_operator_apply(this, psib, hpsib)
178 class(magnus4_operator_t), intent(in) :: this
179 class(batch_t), intent(inout) :: psib
180 class(batch_t), intent(inout) :: hpsib
181
182 integer :: ispin
183 type(wfs_elec_t) :: auxpsib, aux2psib
184
185 push_sub(magnus4_operator_apply)
186
187 select type(hm => this%hm)
188 class is (hamiltonian_elec_t)
189 select type (psib)
190 class is (wfs_elec_t)
191 select type (hpsib)
192 class is (wfs_elec_t)
193 ! We will assume, for the moment, no spinors.
194 if (hm%d%dim /= 1) call messages_not_implemented("Magnus with spinors", namespace=this%namespace)
195
196 assert(psib%nst == hpsib%nst)
197
198 ispin = hm%d%get_spin_index(psib%ik)
199
200 call hpsib%copy_to(auxpsib, copy_data=.false.)
201 call hpsib%copy_to(aux2psib, copy_data=.false.)
202
203 ! Compute (T + Vnl)|psi> and store it
204 call zhamiltonian_elec_apply_batch(hm, this%namespace, this%mesh, psib, auxpsib, &
206
207 ! H|psi> = (T + Vnl)|psi> + Vpsl|psi> + Vmagnus(t2)|psi> + Vborders|psi>
208 call auxpsib%copy_data_to(this%mesh%np, hpsib)
209 call zhamiltonian_elec_external(hm, this%mesh, psib, hpsib)
210 if (hm%abs_boundaries%abtype == imaginary_absorbing) then
211 call batch_mul(this%mesh%np, hm%abs_boundaries%mf(1:this%mesh%np), psib, aux2psib)
212 call batch_axpy(this%mesh%np, m_zi, aux2psib, hpsib)
213 end if
214 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 2), psib, aux2psib)
215 call batch_axpy(this%mesh%np, m_one, aux2psib, hpsib)
216
217 ! Add first term of the commutator: - i Vmagnus(t1) (T + Vnl) |psi>
218 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 1), auxpsib, aux2psib)
219 call batch_axpy(this%mesh%np, -m_zi, aux2psib, hpsib)
220
221 ! Add second term of commutator: i (T + Vnl) Vmagnus(t1) |psi>
222 call batch_mul(this%mesh%np, this%vmagnus(1:this%mesh%np, ispin, 1), psib, auxpsib)
223 call zhamiltonian_elec_apply_batch(hm, this%namespace, this%mesh, auxpsib, aux2psib, &
225 call batch_axpy(this%mesh%np, m_zi, aux2psib, hpsib)
226
227 call auxpsib%end()
228 call aux2psib%end()
229 class default
230 message(1) = "Internal error: imcompatible batch_t in magnus4_operator_apply for argument hpsib."
231 call messages_fatal(1, namespace=this%namespace)
232 end select
233 class default
234 message(1) = "Internal error: imcompatible batch_t in magnus4_operator_apply for argument psib."
235 call messages_fatal(1, namespace=this%namespace)
236 end select
237 end select
238
240 end subroutine magnus4_operator_apply
241
242 ! ---------------------------------------------------------
244 subroutine td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, iter)
245 type(v_ks_t), target, intent(inout) :: ks
246 type(namespace_t), intent(in) :: namespace
247 type(electron_space_t), intent(in) :: space
248 type(hamiltonian_elec_t), target, intent(inout) :: hm
249 type(grid_t), target, intent(in) :: gr
250 type(states_elec_t), target, intent(inout) :: st
251 type(propagator_base_t), target, intent(inout) :: tr
252 real(real64), intent(in) :: time
253 real(real64), intent(in) :: dt
254 type(ion_dynamics_t), intent(inout) :: ions_dyn
255 type(ions_t), intent(inout) :: ions
256 type(partner_list_t), intent(in) :: ext_partners
257 integer, intent(in) :: iter
258
259 real(real64) :: alpha1, alpha2, c1, c2, t1, t2
260 real(real64), allocatable :: vhxc1(:, :), vhxc2(:, :)
261
262 if (ions_dyn%is_active() .or. list_has_gauge_field(ext_partners)) then
263 message(1) = "The commutator-free Magnus expansion cannot be used with moving ions, cell dynamics, or gauge fields"
264 call messages_fatal(1, namespace=namespace)
265 end if
266
267 push_sub(propagator_dt.td_cfmagnus4)
268
269 if (iter < 4) then
270 call td_explicit_runge_kutta4(ks, namespace, space, hm, gr, st, time, dt, ions_dyn, ions, ext_partners)
271 pop_sub(propagator_dt.td_cfmagnus4)
272 return
273 end if
274
275
276 alpha1 = (m_three - m_two * sqrt(m_three))/12.0_real64
277 alpha2 = (m_three + m_two * sqrt(m_three))/12.0_real64
278 c1 = m_half - sqrt(m_three)/6.0_real64
279 c2 = m_half + sqrt(m_three)/6.0_real64
280 t1 = time - dt + c1*dt
281 t2 = time - dt + c2*dt
282
283 safe_allocate(vhxc1(1:gr%np, 1:st%d%nspin))
284 safe_allocate(vhxc2(1:gr%np, 1:st%d%nspin))
285
286 call potential_interpolation_interpolate(tr%vks_old, 4, time, dt, t1, vhxc1)
287 call potential_interpolation_interpolate(tr%vks_old, 4, time, dt, t2, vhxc2)
288
289 hm%ks_pot%vhxc(:, :) = m_two * (alpha2 * vhxc1(:, :) + alpha1 * vhxc2(:, :))
290 call hamiltonian_elec_update_with_ext_pot(hm, gr, space, ext_partners, (/ t1, t2 /), (/ m_two * alpha2, m_two * alpha1 /))
291 ! propagate by dt/2
292 call propagation_ops_elec_exp_apply(tr%te, namespace, st, gr, hm, m_half*dt)
293
294 hm%ks_pot%vhxc(:, :) = m_two * (alpha1 * vhxc1(:, :) + alpha2 * vhxc2(:, :))
295 call hamiltonian_elec_update_with_ext_pot(hm, gr, space, ext_partners, (/ t1, t2 /), (/ m_two * alpha1, m_two * alpha2 /))
296 ! propagate by dt/2
297 !TODO: fuse this with density calc
298 call propagation_ops_elec_exp_apply(tr%te, namespace, st, gr, hm, m_half * dt)
299
300 call density_calc(st, gr, st%rho)
301
302 safe_deallocate_a(vhxc1)
303 safe_deallocate_a(vhxc2)
304 pop_sub(propagator_dt.td_cfmagnus4)
305 end subroutine td_cfmagnus4
306
308
309!! Local Variables:
310!! mode: f90
311!! coding: utf-8
312!! End:
batchified version of the BLAS axpy routine:
Definition: batch_ops.F90:156
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
subroutine, public density_calc(st, gr, density, istin)
Computes the density from the orbitals in st.
Definition: density.F90:612
logical function, public list_has_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
integer, parameter, public independent_particles
Theory level.
Definition: global.F90:237
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_update_with_ext_pot(this, mesh, space, ext_partners, time, mu)
This is an extension of "hamiltonian_elec_update_pot" to be used by the CFM4 propagator....
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
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1091
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 potential_interpolation_interpolate(potential_interpolation, order, time, dt, t, vhxc, vtau)
subroutine, public propagation_ops_elec_fuse_density_exp_apply(te, namespace, st, gr, hm, dt, dt2, op)
subroutine, public propagation_ops_elec_exp_apply(te, namespace, st, mesh, hm, dt, op)
subroutine, public td_cfmagnus4(ks, namespace, space, hm, gr, st, tr, time, dt, ions_dyn, ions, ext_partners, iter)
Commutator-free Magnus propagator of order 4.
subroutine magnus4_operator_apply(this, psib, hpsib)
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_explicit_runge_kutta4(ks, namespace, space, hm, gr, st, time, dt, ions_dyn, ions, ext_partners, qcchi)
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:593
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 states_elec_t class contains all electronic wave functions.
batches of electronic states
Definition: wfs_elec.F90:141