Octopus
propagation_ops_elec.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 N. Tancogne-Dejean
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
22 use accel_oct_m
23 use batch_oct_m
24 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
36 use ions_oct_m
37 use, intrinsic :: iso_fortran_env
38 use lasers_oct_m
39 use lda_u_oct_m
41 use mesh_oct_m
48 use space_oct_m
52 use xc_oct_m
53
54 implicit none
55
56 private
57 public :: &
70
72 private
73 type(ion_state_t) :: ions_state
74 real(real64), allocatable :: vecpot(:), vecpot_vel(:)
76
77
78contains
79
80 ! ---------------------------------------------------------
81 subroutine propagation_ops_elec_update_hamiltonian(namespace, space, st, mesh, hm, ext_partners, time)
82 type(namespace_t), intent(in) :: namespace
83 class(space_t), intent(in) :: space
84 type(states_elec_t), intent(inout) :: st
85 class(mesh_t), intent(in) :: mesh
86 type(hamiltonian_elec_t), intent(inout) :: hm
87 type(partner_list_t), intent(in) :: ext_partners
88 real(real64), intent(in) :: time
89
90
92
93 call profiling_in('ELEC_UPDATE_H')
94
95 call calculate_mxll_dipole_field(hm, mesh, st)
96 call hm%update(mesh, namespace, space, ext_partners, time = time)
97 call lda_u_update_occ_matrices(hm%lda_u, namespace, mesh, st, hm%hm_base, hm%phase, hm%energy)
98
99 call profiling_out('ELEC_UPDATE_H')
100
103
104
105 ! ---------------------------------------------------------
106 subroutine propagation_ops_elec_move_ions(wo, gr, hm, st, namespace, space, ions_dyn, ions, &
107 ext_partners, time, dt, save_pos)
108 class(propagation_ops_elec_t), intent(inout) :: wo
109 type(grid_t), intent(in) :: gr
110 type(hamiltonian_elec_t), intent(inout) :: hm
111 type(states_elec_t), intent(inout) :: st
112 type(namespace_t), intent(in) :: namespace
113 type(electron_space_t), intent(in) :: space
114 type(ion_dynamics_t), intent(inout) :: ions_dyn
115 type(ions_t), intent(inout) :: ions
116 type(partner_list_t), intent(in) :: ext_partners
117 real(real64), intent(in) :: time
118 real(real64), intent(in) :: dt
119 logical, optional, intent(in) :: save_pos
120
121 real(real64) :: dt_ions
122
124
125 call profiling_in('ELEC_MOVE_IONS')
126
127
128 if (ion_dynamics_ions_move(ions_dyn)) then
129 dt_ions = dt * ions_dyn%ionic_scale
130 if (optional_default(save_pos, .false.)) then
131 call ion_dynamics_save_state(ions_dyn, ions, wo%ions_state)
132 end if
133 call ion_dynamics_propagate(ions_dyn, ions, time, dt_ions, namespace)
134 call hamiltonian_elec_epot_generate(hm, namespace, space, gr, ions, ext_partners, st, time = time)
135 end if
136
137 call profiling_out('ELEC_MOVE_IONS')
138
140 end subroutine propagation_ops_elec_move_ions
141
142 ! ---------------------------------------------------------
143 subroutine propagation_ops_elec_restore_ions(wo, ions_dyn, ions)
144 class(propagation_ops_elec_t), intent(inout) :: wo
145 type(ion_dynamics_t), intent(inout) :: ions_dyn
146 type(ions_t), intent(inout) :: ions
147
148
150
151 call profiling_in('ELEC_RESTORE_IONS')
152
153 if (ion_dynamics_ions_move(ions_dyn)) then
154 call ion_dynamics_restore_state(ions_dyn, ions, wo%ions_state)
155 end if
156
157 call profiling_out('ELEC_RESTORE_IONS')
158
161
162 ! ---------------------------------------------------------
163 subroutine propagation_ops_elec_propagate_gauge_field(wo, gfield, dt, time, save_gf)
164 class(propagation_ops_elec_t), intent(inout) :: wo
165 type(gauge_field_t), intent(inout) :: gfield
166 real(real64), intent(in) :: dt
167 real(real64), intent(in) :: time
168 logical, optional, intent(in) :: save_gf
169
170
172
173 call profiling_in('ELEC_MOVE_GAUGE')
175 if (gauge_field_is_propagated(gfield)) then
176 if (optional_default(save_gf, .false.)) then
177 safe_allocate(wo%vecpot(1:gfield%space%dim))
178 safe_allocate(wo%vecpot_vel(1:gfield%space%dim))
179 call gauge_field_get_vec_pot(gfield, wo%vecpot)
180 call gauge_field_get_vec_pot_vel(gfield, wo%vecpot_vel)
181 end if
183 end if
184
185 call profiling_out('ELEC_MOVE_GAUGE')
186
189
190 ! ---------------------------------------------------------
191 subroutine propagation_ops_elec_restore_gauge_field(wo, namespace, space, hm, mesh, ext_partners)
192 class(propagation_ops_elec_t), intent(inout) :: wo
193 type(namespace_t), intent(in) :: namespace
194 class(space_t), intent(in) :: space
195 type(hamiltonian_elec_t), intent(inout) :: hm
196 class(mesh_t), intent(in) :: mesh
197 type(partner_list_t), intent(in) :: ext_partners
198
199 type(gauge_field_t), pointer :: gfield
200
202
203 call profiling_in('ELEC_RESTORE_GAUGE')
204
205 gfield => list_get_gauge_field(ext_partners)
206 if (associated(gfield)) then
207 call gauge_field_set_vec_pot(gfield, wo%vecpot)
208 call gauge_field_set_vec_pot_vel(gfield, wo%vecpot_vel)
209 safe_deallocate_a(wo%vecpot)
210 safe_deallocate_a(wo%vecpot_vel)
211 call hm%update(mesh, namespace, space, ext_partners)
212 end if
213
214 call profiling_out('ELEC_RESTORE_GAUGE')
215
218
219 ! ---------------------------------------------------------
220 subroutine propagation_ops_elec_exp_apply(te, namespace, st, mesh, hm, dt)
221 type(exponential_t), intent(inout) :: te
222 type(namespace_t), intent(in) :: namespace
223 type(states_elec_t), intent(inout) :: st
224 class(mesh_t), intent(in) :: mesh
225 type(hamiltonian_elec_t), intent(inout) :: hm
226 real(real64), intent(in) :: dt
227
228 integer :: ik, ib
229
231
232 call profiling_in('ELEC_EXP_APPLY')
233
234 do ik = st%d%kpt%start, st%d%kpt%end
235 call propagation_ops_do_pack(st, hm, st%group%block_start, ik)
236 do ib = st%group%block_start, st%group%block_end
237 if (ib + 1 <= st%group%block_end) call propagation_ops_do_pack(st, hm, ib+1, ik)
238 call accel_set_stream(ib)
239
240 call hm%phase%set_phase_corr(mesh, st%group%psib(ib, ik), async=.true.)
241 if (hamiltonian_elec_inh_term(hm)) then
242 call te%apply_batch(namespace, mesh, hm, st%group%psib(ib, ik), dt, &
243 inh_psib = hm%inh_st%group%psib(ib, ik))
244 else
245 call te%apply_batch(namespace, mesh, hm, st%group%psib(ib, ik), dt)
246 end if
247 call hm%phase%unset_phase_corr(mesh, st%group%psib(ib, ik))
248
249 call propagation_ops_do_unpack(st, hm, ib, ik)
250 if (ib-1 >= st%group%block_start) call propagation_ops_finish_unpack(st, hm, ib-1, ik)
251 end do
252 call propagation_ops_finish_unpack(st, hm, st%group%block_end, ik)
253 end do
254
255 call accel_finish()
257 call profiling_out('ELEC_EXP_APPLY')
258
260
261 end subroutine propagation_ops_elec_exp_apply
262
263 ! ---------------------------------------------------------
264 subroutine propagation_ops_elec_fuse_density_exp_apply(te, namespace, st, gr, hm, dt, dt2, vmagnus)
265 type(exponential_t), intent(inout) :: te
266 type(namespace_t), intent(in) :: namespace
267 type(states_elec_t), intent(inout) :: st
268 type(grid_t), intent(in) :: gr
269 type(hamiltonian_elec_t), intent(inout) :: hm
270 real(real64), intent(in) :: dt
271 real(real64), optional, intent(in) :: dt2
272 real(real64), optional, intent(in) :: vmagnus(:,:,:)
273
274 integer :: ik, ib
275 type(wfs_elec_t) :: zpsib_dt
276 type(density_calc_t) :: dens_calc
277
279
280 call profiling_in('ELEC_FUSE_DENS_EXP_APPLY')
281
282 call density_calc_init(dens_calc, st, gr, st%rho)
283
284 do ik = st%d%kpt%start, st%d%kpt%end
285 call propagation_ops_do_pack(st, hm, st%group%block_start, ik)
286 do ib = st%group%block_start, st%group%block_end
287 if (ib + 1 <= st%group%block_end) call propagation_ops_do_pack(st, hm, ib+1, ik)
288 call accel_set_stream(ib)
289
290 call hm%phase%set_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
291 if (present(dt2)) then
292 call st%group%psib(ib, ik)%copy_to(zpsib_dt)
293 if (st%group%psib(ib, ik)%is_packed()) call zpsib_dt%do_pack(copy = .false.)
294
295 !propagate the state to dt/2 and dt, simultaneously, with H(time - dt)
296 if (hamiltonian_elec_inh_term(hm)) then
297 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, psib2 = zpsib_dt, &
298 deltat2 = dt2, inh_psib = hm%inh_st%group%psib(ib, ik))
299 else
300 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, psib2 = zpsib_dt, &
301 deltat2 = dt2)
302 end if
303 call hm%phase%unset_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
304
305 !use the dt propagation to calculate the density
306 call density_calc_accumulate(dens_calc, zpsib_dt)
307
308 call zpsib_dt%end()
309 else
310 !propagate the state to dt with H(time - dt)
311 if (hamiltonian_elec_inh_term(hm)) then
312 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, vmagnus=vmagnus, &
313 inh_psib = hm%inh_st%group%psib(ib, ik))
314 else
315 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, vmagnus=vmagnus)
316 end if
317 call hm%phase%unset_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
318
319 !use the dt propagation to calculate the density
320 call density_calc_accumulate(dens_calc, st%group%psib(ib, ik), async=.true.)
321 end if
322
323 call propagation_ops_do_unpack(st, hm, ib, ik)
324 if (ib-1 >= st%group%block_start) call propagation_ops_finish_unpack(st, hm, ib-1, ik)
325 end do
326 call propagation_ops_finish_unpack(st, hm, st%group%block_end, ik)
327 end do
328
329 call density_calc_end(dens_calc)
330
331 call accel_finish()
332
333 call profiling_out('ELEC_FUSE_DENS_EXP_APPLY')
334
337
338 ! ---------------------------------------------------------
339 subroutine propagation_ops_do_pack(st, hm, ib, ik)
340 type(states_elec_t), intent(inout) :: st
341 type(hamiltonian_elec_t), intent(inout) :: hm
342 integer, intent(in) :: ib
343 integer, intent(in) :: ik
344
346 if (hm%apply_packed()) then
347 call accel_set_stream(ib)
348 call st%group%psib(ib, ik)%do_pack(async=.true.)
349 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%do_pack(async=.true.)
350 end if
352 end subroutine propagation_ops_do_pack
353
354 ! ---------------------------------------------------------
355 subroutine propagation_ops_do_unpack(st, hm, ib, ik)
356 type(states_elec_t), intent(inout) :: st
357 type(hamiltonian_elec_t), intent(inout) :: hm
358 integer, intent(in) :: ib
359 integer, intent(in) :: ik
360
362 if (hm%apply_packed()) then
363 call accel_set_stream(ib)
364 call st%group%psib(ib, ik)%do_unpack(async=.true.)
365 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%do_unpack(async=.true.)
366 end if
368 end subroutine propagation_ops_do_unpack
369
370 ! ---------------------------------------------------------
371 subroutine propagation_ops_finish_unpack(st, hm, ib, ik)
372 type(states_elec_t), intent(inout) :: st
373 type(hamiltonian_elec_t), intent(inout) :: hm
374 integer, intent(in) :: ib
375 integer, intent(in) :: ik
376
378 if (hm%apply_packed()) then
379 call accel_set_stream(ib)
380 call st%group%psib(ib, ik)%finish_unpack()
381 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%finish_unpack()
382 end if
384 end subroutine propagation_ops_finish_unpack
385
386 ! ---------------------------------------------------------
387 subroutine propagation_ops_elec_interpolate_get(mesh, hm, interp)
388 class(mesh_t), intent(in) :: mesh
389 type(hamiltonian_elec_t), intent(inout) :: hm
390 type(potential_interpolation_t), intent(inout) :: interp
391
393
394 call potential_interpolation_get(interp, mesh%np, hm%d%nspin, 0, hm%vhxc, vtau = hm%vtau)
395
397
399
400 ! ---------------------------------------------------------
401 subroutine calculate_mxll_dipole_field(hm, mesh, st)
402 type(hamiltonian_elec_t), target,intent(inout) :: hm
403 class(mesh_t), intent(in) :: mesh
404 type(states_elec_t), intent(in) :: st
405
406 real(real64), parameter :: density_threshold = 1.0e-8_real64
407 integer :: idir
408
409 if (.not. hm%mxll%calc_field_dip) return
410
411 select case (hm%mxll%coupling_mode)
413 if (hm%mxll%add_electric_dip) then
414 hm%mxll%e_field_dip = get_field_dip(hm%mxll%e_field)
415 end if
416 if (hm%mxll%add_magnetic_dip) then
417 hm%mxll%b_field_dip = get_field_dip(hm%mxll%b_field)
418 end if
420 hm%mxll%vec_pot_dip = get_field_dip(hm%mxll%vec_pot)
421 case default
422 return
423 end select
424
425 contains
426
427 function get_field_dip(field_full) result(field_dip)
428 real(real64) :: field_dip(3)
429 real(real64), intent(in) :: field_full(:,:)
430
431 real(real64), allocatable :: total_density(:), mask_density(:)
432 real(real64) :: integral_mask
433
434 field_dip(1:3) = m_zero
435
436 select case (hm%mxll%dipole_field)
437 case (dipole_average)
438 safe_allocate(total_density(1:mesh%np))
439 safe_allocate(mask_density(size(total_density)))
440 total_density = sum(st%rho(1:mesh%np,:), dim=2)
441 ! This mask defines a region in which the fields are averaged
442 ! The region is determined by a non-zero electronic density (density > density_threshold)
443 ! The purpose of defining a region is to average the EM fields in regions overlapping with the
444 ! electronic system, and not including values of the EM fields in the rest of the box.
445 mask_density = merge(m_one, m_zero, total_density > density_threshold)
446 integral_mask = dmf_integrate(mesh, mask_density)
447 do idir = 1, mesh%box%dim
448 field_dip(idir) = dmf_integrate(mesh, mask_density*field_full(:,idir))/integral_mask
449 end do
450 safe_deallocate_a(total_density)
451 safe_deallocate_a(mask_density)
452
453 case (dipole_at_com)
454 if (mesh%mpi_grp%rank == hm%mxll%center_of_mass_rankmin) then
455 field_dip(1:3) = field_full(hm%mxll%center_of_mass_ip,1:3)
456 end if
457 if (mesh%parallel_in_domains) call mesh%allreduce(field_dip(:))
458 end select
459
460 end function get_field_dip
461
462 end subroutine calculate_mxll_dipole_field
463
466
467
468!! Local Variables:
469!! mode: f90
470!! coding: utf-8
471!! End:
subroutine, public accel_finish()
Definition: accel.F90:1296
subroutine, public accel_set_stream(stream_number)
Definition: accel.F90:2196
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements a calculator for the density and defines related functions.
Definition: density.F90:120
subroutine, public density_calc_end(this, allreduce, symmetrize)
Finalize the density calculation.
Definition: density.F90:557
subroutine, public density_calc_accumulate(this, psib, async)
Accumulate weighted orbital densities for a batch psib.
Definition: density.F90:390
subroutine, public density_calc_init(this, st, gr, density)
initialize the density calculator
Definition: density.F90:186
type(gauge_field_t) function, pointer, public list_get_gauge_field(partners)
subroutine, public gauge_field_set_vec_pot_vel(this, vec_pot_vel)
subroutine, public gauge_field_set_vec_pot(this, vec_pot)
subroutine, public gauge_field_get_vec_pot(this, vec_pot)
subroutine, public gauge_field_do_algorithmic_operation(this, operation, dt, time)
subroutine, public gauge_field_get_vec_pot_vel(this, vec_pot_vel)
logical pure function, public gauge_field_is_propagated(this)
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_one
Definition: global.F90:188
This module implements the underlying real-space grid.
Definition: grid.F90:117
subroutine, public hamiltonian_elec_epot_generate(this, namespace, space, gr, ions, ext_partners, st, time)
pure logical function, public hamiltonian_elec_inh_term(hm)
This module defines classes and functions for interaction partners.
subroutine, public ion_dynamics_restore_state(this, ions, state)
subroutine, public ion_dynamics_propagate(this, ions, time, dt, namespace)
subroutine, public ion_dynamics_save_state(this, ions, state)
logical pure function, public ion_dynamics_ions_move(this)
subroutine, public lda_u_update_occ_matrices(this, namespace, mesh, st, hm_base, phase, energy)
Definition: lda_u.F90:796
This module defines various routines, operating on mesh functions.
real(real64) function, public dmf_integrate(mesh, ff, mask, reduce)
Integrate a function on the mesh.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer, parameter, public length_gauge_dipole
integer, parameter, public dipole_average
integer, parameter, public velocity_gauge_dipole
integer, parameter, public multipolar_expansion
integer, parameter, public dipole_at_com
subroutine, public potential_interpolation_get(potential_interpolation, np, nspin, i, vhxc, vtau)
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:623
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:552
subroutine, public propagation_ops_elec_restore_ions(wo, ions_dyn, ions)
subroutine, public propagation_ops_elec_move_ions(wo, gr, hm, st, namespace, space, ions_dyn, ions, ext_partners, time, dt, save_pos)
subroutine, public propagation_ops_elec_propagate_gauge_field(wo, gfield, dt, time, save_gf)
subroutine, public propagation_ops_do_unpack(st, hm, ib, ik)
subroutine, public propagation_ops_elec_update_hamiltonian(namespace, space, st, mesh, hm, ext_partners, time)
subroutine, public propagation_ops_elec_exp_apply(te, namespace, st, mesh, hm, dt)
subroutine, public propagation_ops_do_pack(st, hm, ib, ik)
subroutine, public propagation_ops_elec_interpolate_get(mesh, hm, interp)
subroutine, public propagation_ops_elec_restore_gauge_field(wo, namespace, space, hm, mesh, ext_partners)
subroutine, public propagation_ops_finish_unpack(st, hm, ib, ik)
subroutine calculate_mxll_dipole_field(hm, mesh, st)
subroutine, public propagation_ops_elec_fuse_density_exp_apply(te, namespace, st, gr, hm, dt, dt2, vmagnus)
type(algorithmic_operation_t), parameter, public op_verlet_compute_acc
Definition: xc.F90:114
real(real64) function, dimension(3) get_field_dip(field_full)
The calculator object.
Definition: density.F90:168
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
Describes mesh distribution to nodes.
Definition: mesh.F90:186
The states_elec_t class contains all electronic wave functions.
batches of electronic states
Definition: wfs_elec.F90:138
int true(void)