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
49 use space_oct_m
53 use xc_oct_m
54
55 implicit none
56
57 private
58 public :: &
72
74 private
75 type(ion_state_t) :: ions_state
76 real(real64), allocatable :: vecpot(:), vecpot_vel(:)
78
79
80contains
81
82 ! ---------------------------------------------------------
83 subroutine propagation_ops_elec_update_hamiltonian(namespace, space, st, mesh, hm, ext_partners, time)
84 type(namespace_t), intent(in) :: namespace
85 class(space_t), intent(in) :: space
86 type(states_elec_t), intent(inout) :: st
87 class(mesh_t), intent(in) :: mesh
88 type(hamiltonian_elec_t), intent(inout) :: hm
89 type(partner_list_t), intent(in) :: ext_partners
90 real(real64), intent(in) :: time
91
92
94
95 call profiling_in('ELEC_UPDATE_H')
96
97 call calculate_mxll_dipole_field(hm, mesh, st)
98 call hm%update(mesh, namespace, space, ext_partners, time = time)
99 call lda_u_update_occ_matrices(hm%lda_u, namespace, mesh, st, hm%hm_base, hm%phase, hm%energy)
100
101 call profiling_out('ELEC_UPDATE_H')
102
105
106
107 ! ---------------------------------------------------------
108 subroutine propagation_ops_elec_move_ions(wo, gr, hm, st, namespace, space, ions_dyn, ions, &
109 ext_partners, mc, time, dt, save_pos)
110 class(propagation_ops_elec_t), intent(inout) :: wo
111 type(grid_t), intent(inout) :: gr
112 type(hamiltonian_elec_t), intent(inout) :: hm
113 type(states_elec_t), intent(inout) :: st
114 type(namespace_t), intent(in) :: namespace
115 type(electron_space_t), intent(in) :: space
116 type(ion_dynamics_t), intent(inout) :: ions_dyn
117 type(ions_t), intent(inout) :: ions
118 type(partner_list_t), intent(in) :: ext_partners
119 type(multicomm_t), intent(inout) :: mc
120 real(real64), intent(in) :: time
121 real(real64), intent(in) :: dt
122 logical, optional, intent(in) :: save_pos
123
124 real(real64) :: dt_ions
125
127
128 call profiling_in('ELEC_MOVE_IONS')
129
130
131 if (ions_dyn%is_active()) then
132 dt_ions = dt * ions_dyn%ionic_scale
133 if (optional_default(save_pos, .false.)) then
134 call ion_dynamics_save_state(ions_dyn, ions, wo%ions_state)
135 end if
136
137 call propagation_ops_elec_propagate_ions_and_cell(gr, hm, st, namespace, space, ions_dyn, ions, &
138 mc, time, dt_ions)
139
140 call hamiltonian_elec_epot_generate(hm, namespace, space, gr, ions, ext_partners, st, time = time)
141 end if
142
143 call profiling_out('ELEC_MOVE_IONS')
144
146 end subroutine propagation_ops_elec_move_ions
147
148 ! ---------------------------------------------------------
149 subroutine propagation_ops_elec_propagate_ions_and_cell(gr, hm, st, namespace, space, ions_dyn, ions, &
150 mc, time, dt_ions)
151 type(grid_t), intent(inout) :: gr
152 type(hamiltonian_elec_t), intent(inout) :: hm
153 type(states_elec_t), intent(inout) :: st
154 type(namespace_t), intent(in) :: namespace
155 type(electron_space_t), intent(in) :: space
156 type(ion_dynamics_t), intent(inout) :: ions_dyn
157 type(ions_t), intent(inout) :: ions
158 type(multicomm_t), intent(inout) :: mc
159 real(real64), intent(in) :: time
160 real(real64), intent(in) :: dt_ions
161
163
164 call ion_dynamics_propagate(ions_dyn, ions, time, dt_ions, namespace)
165
166 ! Update lattice vectors and regenerate grid
167 if (ions_dyn%cell_relax()) then
168 call electrons_lattice_vectors_update(namespace, gr, space, hm%psolver, hm%kpoints, &
169 mc, st%qtot, ions%latt)
170 end if
171
174
175 ! ---------------------------------------------------------
176 subroutine propagation_ops_elec_restore_ions(wo, ions_dyn, ions)
177 class(propagation_ops_elec_t), intent(inout) :: wo
178 type(ion_dynamics_t), intent(inout) :: ions_dyn
179 type(ions_t), intent(inout) :: ions
180
181
183
184 call profiling_in('ELEC_RESTORE_IONS')
185
186 if (ions_dyn%is_active()) then
187 call ion_dynamics_restore_state(ions_dyn, ions, wo%ions_state)
188 end if
189
190 call profiling_out('ELEC_RESTORE_IONS')
191
194
195 ! ---------------------------------------------------------
196 subroutine propagation_ops_elec_propagate_gauge_field(wo, gfield, dt, time, save_gf)
197 class(propagation_ops_elec_t), intent(inout) :: wo
198 type(gauge_field_t), intent(inout) :: gfield
199 real(real64), intent(in) :: dt
200 real(real64), intent(in) :: time
201 logical, optional, intent(in) :: save_gf
202
203
205
206 call profiling_in('ELEC_MOVE_GAUGE')
207
208 if (gauge_field_is_propagated(gfield)) then
209 if (optional_default(save_gf, .false.)) then
210 safe_allocate(wo%vecpot(1:gfield%space%dim))
211 safe_allocate(wo%vecpot_vel(1:gfield%space%dim))
212 call gauge_field_get_vec_pot(gfield, wo%vecpot)
213 call gauge_field_get_vec_pot_vel(gfield, wo%vecpot_vel)
214 end if
216 end if
217
218 call profiling_out('ELEC_MOVE_GAUGE')
219
222
223 ! ---------------------------------------------------------
224 subroutine propagation_ops_elec_restore_gauge_field(wo, namespace, space, hm, mesh, ext_partners)
225 class(propagation_ops_elec_t), intent(inout) :: wo
226 type(namespace_t), intent(in) :: namespace
227 class(space_t), intent(in) :: space
228 type(hamiltonian_elec_t), intent(inout) :: hm
229 class(mesh_t), intent(in) :: mesh
230 type(partner_list_t), intent(in) :: ext_partners
231
232 type(gauge_field_t), pointer :: gfield
233
235
236 call profiling_in('ELEC_RESTORE_GAUGE')
237
238 gfield => list_get_gauge_field(ext_partners)
239 if (associated(gfield)) then
240 call gauge_field_set_vec_pot(gfield, wo%vecpot)
241 call gauge_field_set_vec_pot_vel(gfield, wo%vecpot_vel)
242 safe_deallocate_a(wo%vecpot)
243 safe_deallocate_a(wo%vecpot_vel)
244 call hm%update(mesh, namespace, space, ext_partners)
245 end if
246
247 call profiling_out('ELEC_RESTORE_GAUGE')
248
251
252 ! ---------------------------------------------------------
253 subroutine propagation_ops_elec_exp_apply(te, namespace, st, mesh, hm, dt)
254 type(exponential_t), intent(inout) :: te
255 type(namespace_t), intent(in) :: namespace
256 type(states_elec_t), intent(inout) :: st
257 class(mesh_t), intent(in) :: mesh
258 type(hamiltonian_elec_t), intent(inout) :: hm
259 real(real64), intent(in) :: dt
260
261 integer :: ik, ib
262
264
265 call profiling_in('ELEC_EXP_APPLY')
266
267 do ik = st%d%kpt%start, st%d%kpt%end
268 call propagation_ops_do_pack(st, hm, st%group%block_start, ik)
269 do ib = st%group%block_start, st%group%block_end
270 if (ib + 1 <= st%group%block_end) call propagation_ops_do_pack(st, hm, ib+1, ik)
271 call accel_set_stream(ib)
272
273 call hm%phase%set_phase_corr(mesh, st%group%psib(ib, ik), async=.true.)
274 if (hamiltonian_elec_inh_term(hm)) then
275 call te%apply_batch(namespace, mesh, hm, st%group%psib(ib, ik), dt, &
276 inh_psib = hm%inh_st%group%psib(ib, ik))
277 else
278 call te%apply_batch(namespace, mesh, hm, st%group%psib(ib, ik), dt)
279 end if
280 call hm%phase%unset_phase_corr(mesh, st%group%psib(ib, ik))
281
282 call propagation_ops_do_unpack(st, hm, ib, ik)
283 if (ib-1 >= st%group%block_start) call propagation_ops_finish_unpack(st, hm, ib-1, ik)
284 end do
285 call propagation_ops_finish_unpack(st, hm, st%group%block_end, ik)
286 end do
287
288 call accel_finish()
290 call profiling_out('ELEC_EXP_APPLY')
291
293
294 end subroutine propagation_ops_elec_exp_apply
295
296 ! ---------------------------------------------------------
297 subroutine propagation_ops_elec_fuse_density_exp_apply(te, namespace, st, gr, hm, dt, dt2, vmagnus)
298 type(exponential_t), intent(inout) :: te
299 type(namespace_t), intent(in) :: namespace
300 type(states_elec_t), intent(inout) :: st
301 type(grid_t), intent(in) :: gr
302 type(hamiltonian_elec_t), intent(inout) :: hm
303 real(real64), intent(in) :: dt
304 real(real64), optional, intent(in) :: dt2
305 real(real64), optional, intent(in) :: vmagnus(:,:,:)
306
307 integer :: ik, ib
308 type(wfs_elec_t) :: zpsib_dt
309 type(density_calc_t) :: dens_calc
310
312
313 call profiling_in('ELEC_FUSE_DENS_EXP_APPLY')
314
315 call density_calc_init(dens_calc, st, gr, st%rho)
316
317 do ik = st%d%kpt%start, st%d%kpt%end
318 call propagation_ops_do_pack(st, hm, st%group%block_start, ik)
319 do ib = st%group%block_start, st%group%block_end
320 if (ib + 1 <= st%group%block_end) call propagation_ops_do_pack(st, hm, ib+1, ik)
321 call accel_set_stream(ib)
322
323 call hm%phase%set_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
324 if (present(dt2)) then
325 call st%group%psib(ib, ik)%copy_to(zpsib_dt)
326 if (st%group%psib(ib, ik)%is_packed()) call zpsib_dt%do_pack(copy = .false.)
327
328 !propagate the state to dt/2 and dt, simultaneously, with H(time - dt)
329 if (hamiltonian_elec_inh_term(hm)) then
330 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, psib2 = zpsib_dt, &
331 deltat2 = dt2, inh_psib = hm%inh_st%group%psib(ib, ik))
332 else
333 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, psib2 = zpsib_dt, &
334 deltat2 = dt2)
335 end if
336 call hm%phase%unset_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
337
338 !use the dt propagation to calculate the density
339 call density_calc_accumulate(dens_calc, zpsib_dt)
340
341 call zpsib_dt%end()
342 else
343 !propagate the state to dt with H(time - dt)
344 if (hamiltonian_elec_inh_term(hm)) then
345 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, vmagnus=vmagnus, &
346 inh_psib = hm%inh_st%group%psib(ib, ik))
347 else
348 call te%apply_batch(namespace, gr, hm, st%group%psib(ib, ik), dt, vmagnus=vmagnus)
349 end if
350 call hm%phase%unset_phase_corr(gr, st%group%psib(ib, ik), async=.true.)
351
352 !use the dt propagation to calculate the density
353 call density_calc_accumulate(dens_calc, st%group%psib(ib, ik), async=.true.)
354 end if
355
356 call propagation_ops_do_unpack(st, hm, ib, ik)
357 if (ib-1 >= st%group%block_start) call propagation_ops_finish_unpack(st, hm, ib-1, ik)
358 end do
359 call propagation_ops_finish_unpack(st, hm, st%group%block_end, ik)
360 end do
361
362 call density_calc_end(dens_calc)
363
364 call accel_finish()
365
366 call profiling_out('ELEC_FUSE_DENS_EXP_APPLY')
367
370
371 ! ---------------------------------------------------------
372 subroutine propagation_ops_do_pack(st, hm, ib, ik)
373 type(states_elec_t), intent(inout) :: st
374 type(hamiltonian_elec_t), intent(inout) :: hm
375 integer, intent(in) :: ib
376 integer, intent(in) :: ik
377
379 if (hm%apply_packed()) then
380 call accel_set_stream(ib)
381 call st%group%psib(ib, ik)%do_pack(async=.true.)
382 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%do_pack(async=.true.)
383 end if
385 end subroutine propagation_ops_do_pack
386
387 ! ---------------------------------------------------------
388 subroutine propagation_ops_do_unpack(st, hm, ib, ik)
389 type(states_elec_t), intent(inout) :: st
390 type(hamiltonian_elec_t), intent(inout) :: hm
391 integer, intent(in) :: ib
392 integer, intent(in) :: ik
393
395 if (hm%apply_packed()) then
396 call accel_set_stream(ib)
397 call st%group%psib(ib, ik)%do_unpack(async=.true.)
398 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%do_unpack(async=.true.)
399 end if
401 end subroutine propagation_ops_do_unpack
402
403 ! ---------------------------------------------------------
404 subroutine propagation_ops_finish_unpack(st, hm, ib, ik)
405 type(states_elec_t), intent(inout) :: st
406 type(hamiltonian_elec_t), intent(inout) :: hm
407 integer, intent(in) :: ib
408 integer, intent(in) :: ik
409
411 if (hm%apply_packed()) then
412 call accel_set_stream(ib)
413 call st%group%psib(ib, ik)%finish_unpack()
414 if (hamiltonian_elec_inh_term(hm)) call hm%inh_st%group%psib(ib, ik)%finish_unpack()
415 end if
417 end subroutine propagation_ops_finish_unpack
418
419 ! ---------------------------------------------------------
420 subroutine propagation_ops_elec_interpolate_get(hm, mesh, vks_old)
421 type(hamiltonian_elec_t), intent(inout) :: hm
422 class(mesh_t), intent(in) :: mesh
423 type(potential_interpolation_t), intent(inout) :: vks_old
424
426
427 call hm%ks_pot%get_interpolated_potentials(vks_old, 0)
428
430
432
433 ! ---------------------------------------------------------
434 subroutine calculate_mxll_dipole_field(hm, mesh, st)
435 type(hamiltonian_elec_t), target,intent(inout) :: hm
436 class(mesh_t), intent(in) :: mesh
437 type(states_elec_t), intent(in) :: st
438
439 real(real64), parameter :: density_threshold = 1.0e-8_real64
440 integer :: idir
441
442 if (.not. hm%mxll%calc_field_dip) return
443
444 select case (hm%mxll%coupling_mode)
446 if (hm%mxll%add_electric_dip) then
447 hm%mxll%e_field_dip = get_field_dip(hm%mxll%e_field)
448 end if
449 if (hm%mxll%add_magnetic_dip) then
450 hm%mxll%b_field_dip = get_field_dip(hm%mxll%b_field)
451 end if
453 hm%mxll%vec_pot_dip = get_field_dip(hm%mxll%vec_pot)
454 case default
455 return
456 end select
457
458 contains
459
460 function get_field_dip(field_full) result(field_dip)
461 real(real64) :: field_dip(3)
462 real(real64), intent(in) :: field_full(:,:)
463
464 real(real64), allocatable :: total_density(:), mask_density(:)
465 real(real64) :: integral_mask
466
467 field_dip(1:3) = m_zero
468
469 select case (hm%mxll%dipole_field)
470 case (dipole_average)
471 safe_allocate(total_density(1:mesh%np))
472 safe_allocate(mask_density(size(total_density)))
473 total_density = sum(st%rho(1:mesh%np,:), dim=2)
474 ! This mask defines a region in which the fields are averaged
475 ! The region is determined by a non-zero electronic density (density > density_threshold)
476 ! The purpose of defining a region is to average the EM fields in regions overlapping with the
477 ! electronic system, and not including values of the EM fields in the rest of the box.
478 mask_density = merge(m_one, m_zero, total_density > density_threshold)
479 integral_mask = dmf_integrate(mesh, mask_density)
480 do idir = 1, mesh%box%dim
481 field_dip(idir) = dmf_integrate(mesh, mask_density*field_full(:,idir))/integral_mask
482 end do
483 safe_deallocate_a(total_density)
484 safe_deallocate_a(mask_density)
485
486 case (dipole_at_com)
487 if (mesh%mpi_grp%rank == hm%mxll%center_of_mass_rankmin) then
488 field_dip(1:3) = field_full(hm%mxll%center_of_mass_ip,1:3)
489 end if
490 call mesh%allreduce(field_dip(:))
491 end select
492
493 end function get_field_dip
494
495 end subroutine calculate_mxll_dipole_field
496
499
500
501!! Local Variables:
502!! mode: f90
503!! coding: utf-8
504!! End:
subroutine, public accel_finish()
Definition: accel.F90:1300
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:559
subroutine, public density_calc_accumulate(this, psib, async)
Accumulate weighted orbital densities for a batch psib.
Definition: density.F90:392
subroutine, public density_calc_init(this, st, gr, density)
initialize the density calculator
Definition: density.F90:188
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:188
real(real64), parameter, public m_one
Definition: global.F90:189
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)
Interface for the ion/cell dynamics.
subroutine, public ion_dynamics_save_state(this, ions, state)
subroutine, public electrons_lattice_vectors_update(namespace, gr, space, psolver, kpoints, mc, qtot, new_latt)
subroutine, public lda_u_update_occ_matrices(this, namespace, mesh, st, hm_base, phase, energy)
Definition: lda_u.F90:798
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
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 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_propagate_gauge_field(wo, gfield, dt, time, save_gf)
subroutine, public propagation_ops_do_unpack(st, hm, ib, ik)
subroutine, public propagation_ops_elec_propagate_ions_and_cell(gr, hm, st, namespace, space, ions_dyn, ions, mc, time, dt_ions)
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_elec_interpolate_get(hm, mesh, vks_old)
subroutine, public propagation_ops_do_pack(st, hm, ib, ik)
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_move_ions(wo, gr, hm, st, namespace, space, ions_dyn, ions, ext_partners, mc, time, dt, save_pos)
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:169
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:169
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:139
int true(void)