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 debug_oct_m
29 use epot_oct_m
30 use global_oct_m
32 use math_oct_m
33 use mesh_oct_m
35 use mpi_oct_m
38 use ps_oct_m
39 use space_oct_m
42 use types_oct_m
44
45 implicit none
46
47 private
48
49 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 contains
84
85 procedure :: init => hamiltonian_elec_base_init
86
87 procedure :: end => hamiltonian_elec_base_end
88
89 procedure :: clear => hamiltonian_elec_base_clear
90
91 procedure :: update_magnetic_terms => hamiltonian_elec_base_update_magnetic_terms
92
93 procedure :: allocate_field => hamiltonian_elec_base_allocate
94
95 procedure :: accel_copy_pot => hamiltonian_elec_base_accel_copy_pot
96
97 procedure :: has_magnetic => hamiltonian_elec_base_has_magnetic
98
99 procedure :: has_zeeman => hamiltonian_elec_base_has_zeeman
100
101 procedure :: has_vector_potential => hamiltonian_elec_base_has_vector_potential
102
103 procedure :: calc_rashba => hamiltonian_elec_base_rashba
104
105 procedure :: dcalc_magnetic => dhamiltonian_elec_base_magnetic
106
107 procedure :: zcalc_magnetic => zhamiltonian_elec_base_magnetic
108
109 procedure :: dcalc_local => dhamiltonian_elec_base_local
110
111 procedure :: zcalc_local => zhamiltonian_elec_base_local
112
114
115 integer, parameter, public :: &
116 TERM_ALL = huge(1), &
117 term_kinetic = 1, &
120 term_others = 8, &
121 term_local_external = 16, &
122 term_mgga = 32, &
123 term_dft_u = 64, &
124 term_rdmft_occ = 128
125
126 integer, parameter, public :: &
127 FIELD_POTENTIAL = 1, &
132
133contains
134
135 ! ---------------------------------------------------------
138 subroutine hamiltonian_elec_base_init(this, nspin, mass, rashba_coupling)
139 class(hamiltonian_elec_base_t), intent(inout) :: this
140 integer, intent(in) :: nspin
141 real(real64), intent(in) :: mass
142 real(real64), intent(in) :: rashba_coupling
143
145
146 this%nspin = nspin
147 this%mass = mass
148 this%rashba_coupling = rashba_coupling
149
151 end subroutine hamiltonian_elec_base_init
152
153 ! ---------------------------------------------------------
156 subroutine hamiltonian_elec_base_end(this)
157 class(hamiltonian_elec_base_t), intent(inout) :: this
161 if (allocated(this%potential) .and. accel_is_enabled()) then
162 call accel_free_buffer(this%potential_accel)
163 if (allocated(this%Impotential)) then
164 call accel_free_buffer(this%impotential_accel)
165 end if
166 end if
167
168 safe_deallocate_a(this%potential)
169 safe_deallocate_a(this%Impotential)
170 safe_deallocate_a(this%vector_potential)
171 safe_deallocate_a(this%uniform_vector_potential)
172 safe_deallocate_a(this%uniform_magnetic_field)
173 safe_deallocate_a(this%magnetic_field)
174 safe_deallocate_a(this%zeeman_pot)
178
179 ! ----------------------------------------------------------
183 !
184 subroutine hamiltonian_elec_base_clear(this, np)
185 class(hamiltonian_elec_base_t), intent(inout) :: this
186 integer, intent(in) :: np
187
188 integer :: ip, ispin
189
190 push_sub(hamiltonian_elec_clear)
191
192 if (allocated(this%potential)) then
193 do ispin = 1, this%nspin
194 !$omp parallel do schedule(static)
195 do ip = 1, np
196 this%potential(ip, ispin) = m_zero
197 end do
198 end do
199 end if
201 if (allocated(this%Impotential)) then
202 do ispin = 1, this%nspin
203 !$omp parallel do schedule(static)
204 do ip = 1, np
205 this%Impotential(ip, ispin) = m_zero
206 end do
207 end do
208 end if
209
210 if (allocated(this%uniform_vector_potential)) then
211 this%uniform_vector_potential = m_zero
212 end if
213
214 if (allocated(this%vector_potential)) then
215 this%vector_potential = m_zero
216 end if
217
218 if (allocated(this%uniform_magnetic_field)) then
219 this%uniform_magnetic_field = m_zero
220 end if
222 if (allocated(this%magnetic_field)) then
223 this%magnetic_field = m_zero
224 end if
225
226 if (allocated(this%zeeman_pot)) then
227 this%zeeman_pot = m_zero
228 end if
229
230 pop_sub(hamiltonian_elec_clear)
231 end subroutine hamiltonian_elec_base_clear
232
234 ! ---------------------------------------------------------------
236 !
237 subroutine hamiltonian_elec_base_allocate(this, mesh, field, complex_potential)
238 class(hamiltonian_elec_base_t), intent(inout) :: this
239 class(mesh_t), intent(in) :: mesh
240 integer, intent(in) :: field
241 logical, intent(in) :: complex_potential
242
243 integer :: ip, ispin
244
246
247 if (bitand(field_potential, field) /= 0) then
248 if (.not. allocated(this%potential)) then
249 safe_allocate(this%potential(1:mesh%np, 1:this%nspin))
250 do ispin = 1, this%nspin
251 !$omp parallel do schedule(static)
252 do ip = 1, mesh%np
253 this%potential(ip, ispin) = m_zero
254 end do
255 end do
256 if (complex_potential) then
257 safe_allocate(this%Impotential(1:mesh%np, 1:this%nspin))
258 do ispin = 1, this%nspin
259 !$omp parallel do schedule(static)
260 do ip = 1, mesh%np
261 this%Impotential(ip, ispin) = m_zero
262 end do
263 end do
264 end if
265 if (accel_is_enabled()) then
266 call accel_create_buffer(this%potential_accel, accel_mem_read_only, type_float, accel_padded_size(mesh%np)*this%nspin)
267 if (complex_potential) then
268 call accel_create_buffer(this%impotential_accel, accel_mem_read_only, type_float, &
269 accel_padded_size(mesh%np)*this%nspin)
270 end if
271 end if
272 end if
273 end if
274
275 if (bitand(field_uniform_vector_potential, field) /= 0) then
276 if (.not. allocated(this%uniform_vector_potential)) then
277 safe_allocate(this%uniform_vector_potential(1:mesh%box%dim))
278 this%uniform_vector_potential = m_zero
279 end if
280 end if
281
282 if (bitand(field_vector_potential, field) /= 0) then
283 if (.not. allocated(this%vector_potential)) then
284 safe_allocate(this%vector_potential(1:mesh%box%dim, 1:mesh%np))
285 this%vector_potential = m_zero
286 end if
287 end if
288
289 if (bitand(field_uniform_magnetic_field, field) /= 0) then
290 if (.not. allocated(this%uniform_magnetic_field)) then
291 safe_allocate(this%uniform_magnetic_field(1:max(mesh%box%dim, 3)))
292 this%uniform_magnetic_field = m_zero
293 end if
294 end if
295
296 if ((bitand(field_magnetic_field, field) /= 0) .or. &
297 bitand(field_uniform_magnetic_field, field) /= 0) then
298 if (.not. allocated(this%magnetic_field)) then
299 safe_allocate(this%magnetic_field(1:mesh%np, 1:max(mesh%box%dim, 3)))
300 this%magnetic_field = m_zero
301 safe_allocate(this%zeeman_pot(1:mesh%np, 1:this%nspin))
302 this%zeeman_pot = m_zero
303 end if
304 end if
305
307 end subroutine hamiltonian_elec_base_allocate
308
309 ! ----------------------------------------------------------
310 !
316 !
317 subroutine hamiltonian_elec_base_update_magnetic_terms(this, mesh, gyromagnetic_ratio, ispin)
318 class(hamiltonian_elec_base_t), intent(inout) :: this
319 class(mesh_t), intent(in) :: mesh
320 real(real64), intent(in) :: gyromagnetic_ratio
321 integer, intent(in) :: ispin
322
323 real(real64) :: b_norm2, cc
324 integer :: idir, ip
325
327
328 if (allocated(this%uniform_vector_potential) .and. allocated(this%vector_potential)) then
329 ! copy the uniform vector potential onto the non-uniform one
330 do idir = 1, mesh%box%dim
331 !$omp parallel do schedule(static)
332 do ip = 1, mesh%np
333 this%vector_potential(idir, ip) = &
334 this%vector_potential(idir, ip) + this%uniform_vector_potential(idir)
335 end do
336 end do
337 safe_deallocate_a(this%uniform_vector_potential)
338 end if
339
340
341 if (.not. allocated(this%magnetic_field)) then
343 return
344 end if
345
346 ! add the Zeeman term
347 ! It reads in the Pauli equation as $\frac{|e|\hbar}{2m} \sigma\cdot\vec{B}$
348 ! The gyromagnetic ratio is twice the magnetic moment of the electron in units of Bohr magneton
349 ! This is why we multiply by $\frac{|g_e|}{2}$.
350 ! The factor 1/c comes from the factor 1/c in front of the vector potential, which leads to
351 ! the Zeeman term starting from the Dirac Hamiltonian.
352 cc = m_half/p_c*gyromagnetic_ratio*m_half
353
354 if (allocated(this%uniform_magnetic_field) ) then
355 !$omp parallel private(ip)
356 do idir = 1, 3
357 !$omp do
358 do ip = 1, mesh%np
359 this%magnetic_field(ip, idir) = this%magnetic_field(ip, idir) + this%uniform_magnetic_field(idir)
360 end do
361 !$omp end do nowait
362 end do
363 !$omp end parallel
364 end if
365
366 select case (ispin)
367 case (spin_polarized)
368 !$omp parallel do private(b_norm2)
369 do ip = 1, mesh%np
370 b_norm2 = norm2(this%magnetic_field(ip, 1:max(mesh%box%dim, 3)))
371 this%zeeman_pot(ip, 1) = cc*b_norm2
372 this%zeeman_pot(ip, 2) = - cc*b_norm2
373 end do
374
375 case (spinors)
376 !$omp parallel do
377 do ip = 1, mesh%np
378 this%zeeman_pot(ip, 1) = cc*this%magnetic_field(ip, 3)
379 this%zeeman_pot(ip, 2) = - cc*this%magnetic_field(ip, 3)
380 this%zeeman_pot(ip, 3) = cc*this%magnetic_field(ip, 1)
381 this%zeeman_pot(ip, 4) = - cc*this%magnetic_field(ip, 2)
382 end do
383 end select
384 safe_deallocate_a(this%uniform_magnetic_field)
385
388
389
390 !--------------------------------------------------------
392 !
393 subroutine hamiltonian_elec_base_accel_copy_pot(this, mesh)
394 class(hamiltonian_elec_base_t), intent(inout) :: this
395 class(mesh_t), intent(in) :: mesh
396
397 integer :: offset, ispin
398
400
401 if (allocated(this%potential) .and. accel_is_enabled()) then
402 offset = 0
403 do ispin = 1, this%nspin
404 call accel_write_buffer(this%potential_accel, mesh%np, this%potential(:, ispin), offset = offset)
405 if(allocated(this%Impotential)) then
406 call accel_write_buffer(this%impotential_accel, mesh%np, this%Impotential(:, ispin), offset = offset)
407 end if
408 offset = offset + accel_padded_size(mesh%np)
409 end do
410 end if
411
414
415 ! ---------------------------------------------------------
417 subroutine hamiltonian_elec_base_accel_rebuild(this, mesh)
418 class(hamiltonian_elec_base_t), intent(inout) :: this
419 class(mesh_t), intent(in) :: mesh
420
421 logical :: complex_potential
422
424
425 if (.not. accel_is_enabled()) then
427 return
428 end if
429
430 call accel_detach_buffer(this%potential_accel)
431 call accel_detach_buffer(this%impotential_accel)
432
433 if (.not. allocated(this%potential)) then
435 return
436 end if
437
438 complex_potential = allocated(this%Impotential)
439
440 call accel_create_buffer(this%potential_accel, accel_mem_read_only, type_float, &
441 accel_padded_size(mesh%np)*this%nspin)
442 if (complex_potential) then
443 call accel_create_buffer(this%impotential_accel, accel_mem_read_only, type_float, &
444 accel_padded_size(mesh%np)*this%nspin)
445 end if
446
447 call this%accel_copy_pot(mesh)
448
451
452 ! ----------------------------------------------------------------------------------
454 !
455 logical pure function hamiltonian_elec_base_has_magnetic(this) result(has_magnetic)
456 class(hamiltonian_elec_base_t), intent(in) :: this
457
458 has_magnetic = allocated(this%vector_potential) &
459 .or. allocated(this%uniform_magnetic_field) &
460 .or. allocated(this%magnetic_field)
461
463
464 ! ----------------------------------------------------------------------------------
466 !
467 logical pure function hamiltonian_elec_base_has_zeeman(this) result(has_zeeman)
468 class(hamiltonian_elec_base_t), intent(in) :: this
469
470 has_zeeman = allocated(this%zeeman_pot)
471
473
474 ! ----------------------------------------------------------------------------------
476 !
477 logical pure function hamiltonian_elec_base_has_vector_potential(this) result(has_vector_potential)
478 class(hamiltonian_elec_base_t), intent(in) :: this
479
480 has_vector_potential = allocated(this%vector_potential) &
481 .or. allocated(this%uniform_vector_potential)
482
484
485 ! ---------------------------------------------------------------------------------------
486 subroutine hamiltonian_elec_base_rashba(this, mesh, der, std, psib, vpsib)
487 class(hamiltonian_elec_base_t), intent(in) :: this
488 class(mesh_t), intent(in) :: mesh
489 type(derivatives_t), intent(in) :: der
490 type(states_elec_dim_t), intent(in) :: std
491 type(wfs_elec_t), target, intent(in) :: psib
492 type(wfs_elec_t), target, intent(inout) :: vpsib
493
494 integer :: ist, idim, ip
495 complex(real64), allocatable :: psi(:, :), vpsi(:, :), grad(:, :, :)
496
498
499 if (abs(this%rashba_coupling) < m_epsilon) then
501 return
502 end if
503 assert(std%ispin == spinors)
504 assert(mesh%box%dim == 2)
505 assert(psib%type() == type_cmplx)
506 assert(vpsib%type() == type_cmplx)
507
508 safe_allocate(psi(1:mesh%np_part, 1:std%dim))
509 safe_allocate(vpsi(1:mesh%np, 1:std%dim))
510 safe_allocate(grad(1:mesh%np, 1:mesh%box%dim, 1:std%dim))
511
512 do ist = 1, psib%nst
513 call batch_get_state(psib, ist, mesh%np_part, psi)
514 call batch_get_state(vpsib, ist, mesh%np, vpsi)
515
516 do idim = 1, std%dim
517 call zderivatives_grad(der, psi(:, idim), grad(:, :, idim), ghost_update = .false., set_bc = .false.)
518 end do
519
520 if (allocated(this%vector_potential)) then
521 do ip = 1, mesh%np
522 vpsi(ip, 1) = vpsi(ip, 1) - &
523 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), this%vector_potential(1, ip), real64) * psi(ip, 2)
524 vpsi(ip, 2) = vpsi(ip, 2) - &
525 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), -this%vector_potential(1, ip), real64) * psi(ip, 1)
526 end do
527 end if
528
529 do ip = 1, mesh%np
530 vpsi(ip, 1) = vpsi(ip, 1) - &
531 this%rashba_coupling*( grad(ip, 1, 2) - m_zi*grad(ip, 2, 2))
532 vpsi(ip, 2) = vpsi(ip, 2) + &
533 this%rashba_coupling*( grad(ip, 1, 1) + m_zi*grad(ip, 2, 1))
534 end do
535
536 call batch_set_state(vpsib, ist, mesh%np, vpsi)
537 end do
538
539 safe_deallocate_a(grad)
540 safe_deallocate_a(vpsi)
541 safe_deallocate_a(psi)
542
544 end subroutine hamiltonian_elec_base_rashba
545
546#include "undef.F90"
547#include "real.F90"
548#include "hamiltonian_elec_base_inc.F90"
549
550#include "undef.F90"
551#include "complex.F90"
552#include "hamiltonian_elec_base_inc.F90"
553
555
556!! Local Variables:
557!! mode: f90
558!! coding: utf-8
559!! End:
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:1006
subroutine, public accel_detach_buffer(this)
Clear a buffer handle without freeing device memory.
Definition: accel.F90:1075
pure logical function, public accel_is_enabled()
Definition: accel.F90:403
integer, parameter, public accel_mem_read_only
Definition: accel.F90:186
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 contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:120
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:200
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:242
logical pure function hamiltonian_elec_base_has_vector_potential(this)
return .true. of the Hamiltonian contains any vector potential
subroutine hamiltonian_elec_base_accel_copy_pot(this, mesh)
copy the potential to the acceleration device buffer
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 zhamiltonian_elec_base_magnetic(this, mesh, der, std, ispin, psib, vpsib)
apply magnetic terms form the Hamiltonian to the wave functions
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
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
subroutine dhamiltonian_elec_base_magnetic(this, mesh, der, std, ispin, psib, vpsib)
apply magnetic terms form the Hamiltonian to the wave functions
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, public hamiltonian_elec_base_accel_rebuild(this, mesh)
Rebuild accelerator buffers after an intrinsic copy.
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:117
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
This module defines non-local operators.
Definition: ps.F90:116
This module handles spin dimensions of the states and the k-point distribution.
type(type_t), parameter, public type_float
Definition: types.F90:135
The basic Hamiltonian for electronic system.
Describes mesh distribution to nodes.
Definition: mesh.F90:187