Octopus
hamiltonian_elec_base.F90
Go to the documentation of this file.
1!! Copyright (C) 2009 X. Andrade
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
25 use blas_oct_m
26 use comm_oct_m
27 use debug_oct_m
30 use epot_oct_m
31 use global_oct_m
33 use math_oct_m
34 use mesh_oct_m
36 use mpi_oct_m
39 use ps_oct_m
40 use space_oct_m
43 use types_oct_m
45
46 implicit none
47
48 private
49
50 public :: &
54
64 private
65 integer :: nspin
66 real(real64) :: mass
67 real(real64) :: rashba_coupling
68 type(nl_operator_t), pointer, public :: kinetic
69 real(real64), allocatable, public :: potential(:, :)
70 real(real64), allocatable, public :: Impotential(:, :)
71 real(real64), allocatable, public :: uniform_magnetic_field(:)
73 real(real64), allocatable, public :: magnetic_field(:, :)
75 real(real64), allocatable, public :: zeeman_pot(:, :)
76 real(real64), allocatable, public :: uniform_vector_potential(:)
80 real(real64), allocatable, public :: vector_potential(:, :)
81 type(accel_mem_t) :: potential_accel
82 type(accel_mem_t) :: impotential_accel
83 type(accel_mem_t), public :: vtau_accel
84 contains
85
86 procedure :: init => hamiltonian_elec_base_init
87
88 procedure :: end => hamiltonian_elec_base_end
89
90 procedure :: clear => hamiltonian_elec_base_clear
91
92 procedure :: update_magnetic_terms => hamiltonian_elec_base_update_magnetic_terms
93
94 procedure :: allocate_field => hamiltonian_elec_base_allocate
95
96 procedure :: accel_copy_pot => hamiltonian_elec_base_accel_copy_pot
97
98 procedure :: has_magnetic => hamiltonian_elec_base_has_magnetic
99
100 procedure :: has_zeeman => hamiltonian_elec_base_has_zeeman
101
102 procedure :: has_vector_potential => hamiltonian_elec_base_has_vector_potential
103
104 procedure :: calc_rashba => hamiltonian_elec_base_rashba
105
106 procedure :: dcalc_magnetic => dhamiltonian_elec_base_magnetic
107
108 procedure :: zcalc_magnetic => zhamiltonian_elec_base_magnetic
109
110 procedure :: dcalc_local => dhamiltonian_elec_base_local
111
112 procedure :: zcalc_local => zhamiltonian_elec_base_local
113
115
116 integer, parameter, public :: &
117 TERM_ALL = huge(1), &
118 term_kinetic = 1, &
121 term_others = 8, &
122 term_local_external = 16, &
123 term_mgga = 32, &
124 term_dft_u = 64, &
125 term_rdmft_occ = 128
126
127 integer, parameter, public :: &
128 FIELD_POTENTIAL = 1, &
133
134contains
135
136 ! ---------------------------------------------------------
139 subroutine hamiltonian_elec_base_init(this, nspin, mass, rashba_coupling)
140 class(hamiltonian_elec_base_t), intent(inout) :: this
141 integer, intent(in) :: nspin
142 real(real64), intent(in) :: mass
143 real(real64), intent(in) :: rashba_coupling
144
146
147 this%nspin = nspin
148 this%mass = mass
149 this%rashba_coupling = rashba_coupling
150
152 end subroutine hamiltonian_elec_base_init
153
154 ! ---------------------------------------------------------
157 subroutine hamiltonian_elec_base_end(this)
158 class(hamiltonian_elec_base_t), intent(inout) :: this
162 if (allocated(this%potential) .and. accel_is_enabled()) then
163 call accel_release_buffer(this%potential_accel)
164 call accel_release_buffer(this%vtau_accel)
165 if (allocated(this%Impotential)) then
166 call accel_release_buffer(this%impotential_accel)
167 end if
168 end if
170 safe_deallocate_a(this%potential)
171 safe_deallocate_a(this%Impotential)
172 safe_deallocate_a(this%vector_potential)
173 safe_deallocate_a(this%uniform_vector_potential)
174 safe_deallocate_a(this%uniform_magnetic_field)
175 safe_deallocate_a(this%magnetic_field)
176 safe_deallocate_a(this%zeeman_pot)
177
180
181 ! ----------------------------------------------------------
182 !
186 subroutine hamiltonian_elec_base_clear(this, np)
187 class(hamiltonian_elec_base_t), intent(inout) :: this
188 integer, intent(in) :: np
190 integer :: ip, ispin
192 push_sub(hamiltonian_elec_clear)
194 if (allocated(this%potential)) then
195 do ispin = 1, this%nspin
196 !$omp parallel do schedule(static)
197 do ip = 1, np
198 this%potential(ip, ispin) = m_zero
199 end do
200 end do
201 end if
202
203 if (allocated(this%Impotential)) then
204 do ispin = 1, this%nspin
205 !$omp parallel do schedule(static)
206 do ip = 1, np
207 this%Impotential(ip, ispin) = m_zero
208 end do
209 end do
210 end if
211
212 if (allocated(this%uniform_vector_potential)) then
213 this%uniform_vector_potential = m_zero
214 end if
215
216 if (allocated(this%vector_potential)) then
217 this%vector_potential = m_zero
218 end if
219
220 if (allocated(this%uniform_magnetic_field)) then
221 this%uniform_magnetic_field = m_zero
222 end if
223
224 if (allocated(this%magnetic_field)) then
225 this%magnetic_field = m_zero
226 end if
227
228 if (allocated(this%zeeman_pot)) then
229 this%zeeman_pot = m_zero
230 end if
231
232 pop_sub(hamiltonian_elec_clear)
233 end subroutine hamiltonian_elec_base_clear
234
235
236 ! ---------------------------------------------------------------
238 !
239 subroutine hamiltonian_elec_base_allocate(this, mesh, field, complex_potential)
240 class(hamiltonian_elec_base_t), intent(inout) :: this
241 class(mesh_t), intent(in) :: mesh
242 integer, intent(in) :: field
243 logical, intent(in) :: complex_potential
244
245 integer :: ip, ispin
246
248
249 if (bitand(field_potential, field) /= 0) then
250 if (.not. allocated(this%potential)) then
251 safe_allocate(this%potential(1:mesh%np, 1:this%nspin))
252 do ispin = 1, this%nspin
253 !$omp parallel do schedule(static)
254 do ip = 1, mesh%np
255 this%potential(ip, ispin) = m_zero
256 end do
257 end do
258 if (complex_potential) then
259 safe_allocate(this%Impotential(1:mesh%np, 1:this%nspin))
260 do ispin = 1, this%nspin
261 !$omp parallel do schedule(static)
262 do ip = 1, mesh%np
263 this%Impotential(ip, ispin) = m_zero
264 end do
265 end do
266 end if
267 if (accel_is_enabled()) then
268 call accel_create_buffer(this%potential_accel, accel_mem_read_only, type_float, accel_padded_size(mesh%np)*this%nspin)
269 call accel_create_buffer(this%vtau_accel, accel_mem_read_only, type_float, accel_padded_size(mesh%np)*this%nspin)
270 if (complex_potential) then
271 call accel_create_buffer(this%impotential_accel, accel_mem_read_only, type_float, &
272 accel_padded_size(mesh%np)*this%nspin)
273 end if
274 end if
275 end if
276 end if
277
278 if (bitand(field_uniform_vector_potential, field) /= 0) then
279 if (.not. allocated(this%uniform_vector_potential)) then
280 safe_allocate(this%uniform_vector_potential(1:mesh%box%dim))
281 this%uniform_vector_potential = m_zero
282 end if
283 end if
284
285 if (bitand(field_vector_potential, field) /= 0) then
286 if (.not. allocated(this%vector_potential)) then
287 safe_allocate(this%vector_potential(1:mesh%box%dim, 1:mesh%np))
288 this%vector_potential = m_zero
289 end if
290 end if
291
292 if (bitand(field_uniform_magnetic_field, field) /= 0) then
293 if (.not. allocated(this%uniform_magnetic_field)) then
294 safe_allocate(this%uniform_magnetic_field(1:max(mesh%box%dim, 3)))
295 this%uniform_magnetic_field = m_zero
296 end if
297 end if
298
299 if ((bitand(field_magnetic_field, field) /= 0) .or. &
300 bitand(field_uniform_magnetic_field, field) /= 0) then
301 if (.not. allocated(this%magnetic_field)) then
302 safe_allocate(this%magnetic_field(1:mesh%np, 1:max(mesh%box%dim, 3)))
303 this%magnetic_field = m_zero
304 safe_allocate(this%zeeman_pot(1:mesh%np, 1:this%nspin))
305 this%zeeman_pot = m_zero
306 end if
307 end if
308
310 end subroutine hamiltonian_elec_base_allocate
311
312 ! ----------------------------------------------------------
313 !
319 !
320 subroutine hamiltonian_elec_base_update_magnetic_terms(this, mesh, gyromagnetic_ratio, ispin)
321 class(hamiltonian_elec_base_t), intent(inout) :: this
322 class(mesh_t), intent(in) :: mesh
323 real(real64), intent(in) :: gyromagnetic_ratio
324 integer, intent(in) :: ispin
325
326 real(real64) :: b_norm2, cc
327 integer :: idir, ip
328
330
331 if (allocated(this%uniform_vector_potential) .and. allocated(this%vector_potential)) then
332 ! copy the uniform vector potential onto the non-uniform one
333 do idir = 1, mesh%box%dim
334 !$omp parallel do schedule(static)
335 do ip = 1, mesh%np
336 this%vector_potential(idir, ip) = &
337 this%vector_potential(idir, ip) + this%uniform_vector_potential(idir)
338 end do
339 end do
340 safe_deallocate_a(this%uniform_vector_potential)
341 end if
342
343
344 if (.not. allocated(this%magnetic_field)) then
346 return
347 end if
348
349 ! add the Zeeman term
350 ! It reads in the Pauli equation as $\frac{|e|\hbar}{2m} \sigma\cdot\vec{B}$
351 ! The gyromagnetic ratio is twice the magnetic moment of the electron in units of Bohr magneton
352 ! This is why we multiply by $\frac{|g_e|}{2}$.
353 ! The factor 1/c comes from the factor 1/c in front of the vector potential, which leads to
354 ! the Zeeman term starting from the Dirac Hamiltonian.
355 cc = m_half/p_c*gyromagnetic_ratio*m_half
356
357 if (allocated(this%uniform_magnetic_field) ) then
358 !$omp parallel private(ip)
359 do idir = 1, 3
360 !$omp do
361 do ip = 1, mesh%np
362 this%magnetic_field(ip, idir) = this%magnetic_field(ip, idir) + this%uniform_magnetic_field(idir)
363 end do
364 !$omp end do nowait
365 end do
366 !$omp end parallel
367 end if
368
369 select case (ispin)
370 case (spin_polarized)
371 !$omp parallel do private(b_norm2)
372 do ip = 1, mesh%np
373 b_norm2 = norm2(this%magnetic_field(ip, 1:max(mesh%box%dim, 3)))
374 this%zeeman_pot(ip, 1) = cc*b_norm2
375 this%zeeman_pot(ip, 2) = - cc*b_norm2
376 end do
377
378 case (spinors)
379 !$omp parallel do
380 do ip = 1, mesh%np
381 this%zeeman_pot(ip, 1) = cc*this%magnetic_field(ip, 3)
382 this%zeeman_pot(ip, 2) = - cc*this%magnetic_field(ip, 3)
383 this%zeeman_pot(ip, 3) = cc*this%magnetic_field(ip, 1)
384 this%zeeman_pot(ip, 4) = - cc*this%magnetic_field(ip, 2)
385 end do
386 end select
387 safe_deallocate_a(this%uniform_magnetic_field)
388
391
392
393 !--------------------------------------------------------
395 !
396 subroutine hamiltonian_elec_base_accel_copy_pot(this, mesh, vtau)
397 class(hamiltonian_elec_base_t), intent(inout) :: this
398 class(mesh_t), intent(in) :: mesh
399 real(real64), optional, intent(in) :: vtau(:,:)
400
401 integer :: offset, ispin
402
404
405 if (allocated(this%potential) .and. accel_is_enabled()) then
406 offset = 0
407 do ispin = 1, this%nspin
408 call accel_write_buffer(this%potential_accel, mesh%np, this%potential(:, ispin), offset = offset)
409 if(present(vtau)) then
410 call accel_write_buffer(this%vtau_accel, mesh%np, vtau(:, ispin), offset = offset)
411 end if
412 if(allocated(this%Impotential)) then
413 call accel_write_buffer(this%impotential_accel, mesh%np, this%Impotential(:, ispin), offset = offset)
414 end if
415 offset = offset + accel_padded_size(mesh%np)
416 end do
417 end if
418
421
422 ! ----------------------------------------------------------------------------------
424 !
425 logical pure function hamiltonian_elec_base_has_magnetic(this) result(has_magnetic)
426 class(hamiltonian_elec_base_t), intent(in) :: this
427
428 has_magnetic = allocated(this%vector_potential) &
429 .or. allocated(this%uniform_magnetic_field)
430
432
433 ! ----------------------------------------------------------------------------------
435 !
436 logical pure function hamiltonian_elec_base_has_zeeman(this) result(has_zeeman)
437 class(hamiltonian_elec_base_t), intent(in) :: this
438
439 has_zeeman = allocated(this%zeeman_pot)
440
442
443 ! ----------------------------------------------------------------------------------
445 !
446 logical pure function hamiltonian_elec_base_has_vector_potential(this) result(has_vector_potential)
447 class(hamiltonian_elec_base_t), intent(in) :: this
448
449 has_vector_potential = allocated(this%vector_potential) &
450 .or. allocated(this%uniform_vector_potential)
451
453
454 ! ---------------------------------------------------------------------------------------
455 subroutine hamiltonian_elec_base_rashba(this, mesh, der, std, psib, vpsib)
456 class(hamiltonian_elec_base_t), intent(in) :: this
457 class(mesh_t), intent(in) :: mesh
458 type(derivatives_t), intent(in) :: der
459 type(states_elec_dim_t), intent(in) :: std
460 type(wfs_elec_t), target, intent(in) :: psib
461 type(wfs_elec_t), target, intent(inout) :: vpsib
462
463 integer :: ist, idim, ip
464 complex(real64), allocatable :: psi(:, :), vpsi(:, :), grad(:, :, :)
465
467
468 if (abs(this%rashba_coupling) < m_epsilon) then
470 return
471 end if
472 assert(std%ispin == spinors)
473 assert(mesh%box%dim == 2)
474 assert(psib%type() == type_cmplx)
475 assert(vpsib%type() == type_cmplx)
476
477 safe_allocate(psi(1:mesh%np_part, 1:std%dim))
478 safe_allocate(vpsi(1:mesh%np, 1:std%dim))
479 safe_allocate(grad(1:mesh%np, 1:mesh%box%dim, 1:std%dim))
480
481 do ist = 1, psib%nst
482 call batch_get_state(psib, ist, mesh%np_part, psi)
483 call batch_get_state(vpsib, ist, mesh%np, vpsi)
484
485 do idim = 1, std%dim
486 call zderivatives_grad(der, psi(:, idim), grad(:, :, idim), ghost_update = .false., set_bc = .false.)
487 end do
488
489 if (allocated(this%vector_potential)) then
490 do ip = 1, mesh%np
491 vpsi(ip, 1) = vpsi(ip, 1) - &
492 (this%rashba_coupling) * (this%vector_potential(2, ip) + m_zi * this%vector_potential(1, ip)) * psi(ip, 2)
493 vpsi(ip, 2) = vpsi(ip, 2) - &
494 (this%rashba_coupling) * (this%vector_potential(2, ip) - m_zi * this%vector_potential(1, ip)) * psi(ip, 1)
495 end do
496 end if
497
498 do ip = 1, mesh%np
499 vpsi(ip, 1) = vpsi(ip, 1) - &
500 this%rashba_coupling*( grad(ip, 1, 2) - m_zi*grad(ip, 2, 2))
501 vpsi(ip, 2) = vpsi(ip, 2) + &
502 this%rashba_coupling*( grad(ip, 1, 1) + m_zi*grad(ip, 2, 1))
503 end do
504
505 call batch_set_state(vpsib, ist, mesh%np, vpsi)
506 end do
507
508 safe_deallocate_a(grad)
509 safe_deallocate_a(vpsi)
510 safe_deallocate_a(psi)
511
513 end subroutine hamiltonian_elec_base_rashba
514
515#include "undef.F90"
516#include "real.F90"
517#include "hamiltonian_elec_base_inc.F90"
519#include "undef.F90"
520#include "complex.F90"
521#include "hamiltonian_elec_base_inc.F90"
522
524
525!! Local Variables:
526!! mode: f90
527!! coding: utf-8
528!! End:
subroutine, public accel_release_buffer(this)
Definition: accel.F90:1246
pure logical function, public accel_is_enabled()
Definition: accel.F90:400
integer, parameter, public accel_mem_read_only
Definition: accel.F90:183
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:118
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
integer, parameter, public spinors
integer, parameter, public spin_polarized
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:223
subroutine dhamiltonian_elec_base_magnetic(this, mesh, der, std, ep, ispin, psib, vpsib)
apply magnetic terms form the Hamiltonian to the wave functions
logical pure function hamiltonian_elec_base_has_vector_potential(this)
return .true. of the Hamiltonian contains any vector potential
subroutine, public dhamiltonian_elec_base_local_sub(potential, mesh, std, ispin, psib, vpsib, Impotential, potential_accel, impotential_accel, async)
apply a local potential to a set of states
subroutine hamiltonian_elec_base_update_magnetic_terms(this, mesh, gyromagnetic_ratio, ispin)
update the magnetic terms of the hamiltonian_elec_base_t.
integer, parameter, public term_local_external
subroutine hamiltonian_elec_base_rashba(this, mesh, der, std, psib, vpsib)
subroutine dhamiltonian_elec_base_local(this, mesh, std, ispin, psib, vpsib, async)
apply the local potential (stored in the hamiltonian) to the states
integer, parameter, public field_uniform_magnetic_field
subroutine hamiltonian_elec_base_allocate(this, mesh, field, complex_potential)
This function ensures that the corresponding field is allocated.
integer, parameter, public field_uniform_vector_potential
integer, parameter, public field_vector_potential
subroutine hamiltonian_elec_base_clear(this, np)
This functions sets to zero all fields that are currently allocated.
logical pure function hamiltonian_elec_base_has_magnetic(this)
return .true. if the Hamiltonian contains any magnetic field
subroutine hamiltonian_elec_base_end(this)
Finalizer for hamiltonian_elec_base_t.
integer, parameter, public term_mgga
integer, parameter, public term_others
subroutine zhamiltonian_elec_base_magnetic(this, mesh, der, std, ep, ispin, psib, vpsib)
apply magnetic terms form the Hamiltonian to the wave functions
integer, parameter, public term_non_local_potential
integer, parameter, public term_rdmft_occ
integer, parameter, public term_kinetic
subroutine zhamiltonian_elec_base_local(this, mesh, std, ispin, psib, vpsib, async)
apply the local potential (stored in the hamiltonian) to the states
logical pure function hamiltonian_elec_base_has_zeeman(this)
return .true. of the Hamiltonian contains a zeeman term
integer, parameter, public field_magnetic_field
subroutine, public zhamiltonian_elec_base_local_sub(potential, mesh, std, ispin, psib, vpsib, Impotential, potential_accel, impotential_accel, async)
apply a local potential to a set of states
subroutine hamiltonian_elec_base_init(this, nspin, mass, rashba_coupling)
initialize the hamiltonian_elec_base_t object
subroutine hamiltonian_elec_base_accel_copy_pot(this, mesh, vtau)
copy the potential to the acceleration device buffer
integer, parameter, public term_dft_u
integer, parameter, public term_local_potential
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
This module defines non-local operators.
Definition: ps.F90:114
This module handles spin dimensions of the states and the k-point distribution.
type(type_t), public type_float
Definition: types.F90:133
The basic Hamiltonian for electronic system.
Describes mesh distribution to nodes.
Definition: mesh.F90:186