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 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
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 ! ---------------------------------------------------------
157 class(hamiltonian_elec_base_t), intent(inout) :: this
161 if (allocated(this%potential) .and. accel_is_enabled()) then
162 call accel_release_buffer(this%potential_accel)
163 if (allocated(this%Impotential)) then
164 call accel_release_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)
177 end subroutine hamiltonian_elec_base_end
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
221
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)
232
233
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 !
418 logical pure function hamiltonian_elec_base_has_magnetic(this) result(has_magnetic)
419 class(hamiltonian_elec_base_t), intent(in) :: this
420
421 has_magnetic = allocated(this%vector_potential) &
422 .or. allocated(this%uniform_magnetic_field)
423
425
426 ! ----------------------------------------------------------------------------------
428 !
429 logical pure function hamiltonian_elec_base_has_zeeman(this) result(has_zeeman)
430 class(hamiltonian_elec_base_t), intent(in) :: this
431
432 has_zeeman = allocated(this%zeeman_pot)
433
435
436 ! ----------------------------------------------------------------------------------
438 !
439 logical pure function hamiltonian_elec_base_has_vector_potential(this) result(has_vector_potential)
440 class(hamiltonian_elec_base_t), intent(in) :: this
441
442 has_vector_potential = allocated(this%vector_potential) &
443 .or. allocated(this%uniform_vector_potential)
444
446
447 ! ---------------------------------------------------------------------------------------
448 subroutine hamiltonian_elec_base_rashba(this, mesh, der, std, psib, vpsib)
449 class(hamiltonian_elec_base_t), intent(in) :: this
450 class(mesh_t), intent(in) :: mesh
451 type(derivatives_t), intent(in) :: der
452 type(states_elec_dim_t), intent(in) :: std
453 type(wfs_elec_t), target, intent(in) :: psib
454 type(wfs_elec_t), target, intent(inout) :: vpsib
455
456 integer :: ist, idim, ip
457 complex(real64), allocatable :: psi(:, :), vpsi(:, :), grad(:, :, :)
458
460
461 if (abs(this%rashba_coupling) < m_epsilon) then
463 return
464 end if
465 assert(std%ispin == spinors)
466 assert(mesh%box%dim == 2)
467 assert(psib%type() == type_cmplx)
468 assert(vpsib%type() == type_cmplx)
469
470 safe_allocate(psi(1:mesh%np_part, 1:std%dim))
471 safe_allocate(vpsi(1:mesh%np, 1:std%dim))
472 safe_allocate(grad(1:mesh%np, 1:mesh%box%dim, 1:std%dim))
473
474 do ist = 1, psib%nst
475 call batch_get_state(psib, ist, mesh%np_part, psi)
476 call batch_get_state(vpsib, ist, mesh%np, vpsi)
477
478 do idim = 1, std%dim
479 call zderivatives_grad(der, psi(:, idim), grad(:, :, idim), ghost_update = .false., set_bc = .false.)
480 end do
481
482 if (allocated(this%vector_potential)) then
483 do ip = 1, mesh%np
484 vpsi(ip, 1) = vpsi(ip, 1) - &
485 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), this%vector_potential(1, ip), real64) * psi(ip, 2)
486 vpsi(ip, 2) = vpsi(ip, 2) - &
487 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), -this%vector_potential(1, ip), real64) * psi(ip, 1)
488 end do
489 end if
490
491 do ip = 1, mesh%np
492 vpsi(ip, 1) = vpsi(ip, 1) - &
493 this%rashba_coupling*( grad(ip, 1, 2) - m_zi*grad(ip, 2, 2))
494 vpsi(ip, 2) = vpsi(ip, 2) + &
495 this%rashba_coupling*( grad(ip, 1, 1) + m_zi*grad(ip, 2, 1))
496 end do
497
498 call batch_set_state(vpsib, ist, mesh%np, vpsi)
499 end do
500
501 safe_deallocate_a(grad)
502 safe_deallocate_a(vpsi)
503 safe_deallocate_a(psi)
504
506 end subroutine hamiltonian_elec_base_rashba
507
508#include "undef.F90"
509#include "real.F90"
510#include "hamiltonian_elec_base_inc.F90"
512#include "undef.F90"
513#include "complex.F90"
514#include "hamiltonian_elec_base_inc.F90"
515
517
518!! Local Variables:
519!! mode: f90
520!! coding: utf-8
521!! 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:188
real(real64), parameter, public m_half
Definition: global.F90:194
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:224
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 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 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
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