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) :: cc, b_perp2
324 integer :: idir, ip
325 logical, save :: warning_shown = .false.
326
328
329 if (allocated(this%uniform_vector_potential) .and. allocated(this%vector_potential)) then
330 ! copy the uniform vector potential onto the non-uniform one
331 do idir = 1, mesh%box%dim
332 !$omp parallel do schedule(static)
333 do ip = 1, mesh%np
334 this%vector_potential(idir, ip) = &
335 this%vector_potential(idir, ip) + this%uniform_vector_potential(idir)
336 end do
337 end do
338 safe_deallocate_a(this%uniform_vector_potential)
339 end if
340
341
342 if (.not. allocated(this%magnetic_field)) then
344 return
345 end if
346
347 ! add the Zeeman term
348 ! It reads in the Pauli equation as $\frac{|e|\hbar}{2m} \sigma\cdot\vec{B}$
349 ! The gyromagnetic ratio is twice the magnetic moment of the electron in units of Bohr magneton
350 ! This is why we multiply by $\frac{|g_e|}{2}$.
351 ! The factor 1/c comes from the factor 1/c in front of the vector potential, which leads to
352 ! the Zeeman term starting from the Dirac Hamiltonian.
353 cc = m_half/p_c*gyromagnetic_ratio*m_half
354
355 if (allocated(this%uniform_magnetic_field) ) then
356 !$omp parallel private(ip)
357 do idir = 1, 3
358 !$omp do
359 do ip = 1, mesh%np
360 this%magnetic_field(ip, idir) = this%magnetic_field(ip, idir) + this%uniform_magnetic_field(idir)
361 end do
362 !$omp end do nowait
363 end do
364 !$omp end parallel
365 end if
366
367 select case (ispin)
368 case (spin_polarized)
369 ! The collinear spin axis is z, as for spinors: only B_z enters, with its sign
370 b_perp2 = m_zero
371 !$omp parallel do reduction(+:b_perp2)
372 do ip = 1, mesh%np
373 this%zeeman_pot(ip, 1) = cc*this%magnetic_field(ip, 3)
374 this%zeeman_pot(ip, 2) = - cc*this%magnetic_field(ip, 3)
375 b_perp2 = b_perp2 + this%magnetic_field(ip, 1)**2 + this%magnetic_field(ip, 2)**2
376 end do
377 call mesh%allreduce(b_perp2)
378 if (b_perp2 > m_epsilon .and. .not. warning_shown) then
379 message(1) = "The magnetic field has x or y components, which do not enter the Zeeman term"
380 message(2) = "for spin-polarized calculations (spin axis z). Use spinors to include them."
381 call messages_warning(2)
382 warning_shown = .true.
383 end if
384
385 case (spinors)
386 !$omp parallel do
387 do ip = 1, mesh%np
388 this%zeeman_pot(ip, 1) = cc*this%magnetic_field(ip, 3)
389 this%zeeman_pot(ip, 2) = - cc*this%magnetic_field(ip, 3)
390 this%zeeman_pot(ip, 3) = cc*this%magnetic_field(ip, 1)
391 this%zeeman_pot(ip, 4) = - cc*this%magnetic_field(ip, 2)
392 end do
393 end select
394 safe_deallocate_a(this%uniform_magnetic_field)
395
398
399
400 !--------------------------------------------------------
402 !
403 subroutine hamiltonian_elec_base_accel_copy_pot(this, mesh)
404 class(hamiltonian_elec_base_t), intent(inout) :: this
405 class(mesh_t), intent(in) :: mesh
406
407 integer :: offset, ispin
408
410
411 if (allocated(this%potential) .and. accel_is_enabled()) then
412 offset = 0
413 do ispin = 1, this%nspin
414 call accel_write_buffer(this%potential_accel, mesh%np, this%potential(:, ispin), offset = offset)
415 if(allocated(this%Impotential)) then
416 call accel_write_buffer(this%impotential_accel, mesh%np, this%Impotential(:, ispin), offset = offset)
417 end if
418 offset = offset + accel_padded_size(mesh%np)
419 end do
420 end if
421
424
425 ! ---------------------------------------------------------
427 subroutine hamiltonian_elec_base_accel_rebuild(this, mesh)
428 class(hamiltonian_elec_base_t), intent(inout) :: this
429 class(mesh_t), intent(in) :: mesh
430
431 logical :: complex_potential
432
434
435 if (.not. accel_is_enabled()) then
437 return
438 end if
439
440 call accel_detach_buffer(this%potential_accel)
441 call accel_detach_buffer(this%impotential_accel)
442
443 if (.not. allocated(this%potential)) then
445 return
446 end if
447
448 complex_potential = allocated(this%Impotential)
449
450 call accel_create_buffer(this%potential_accel, accel_mem_read_only, type_float, &
451 accel_padded_size(mesh%np)*this%nspin)
452 if (complex_potential) then
453 call accel_create_buffer(this%impotential_accel, accel_mem_read_only, type_float, &
454 accel_padded_size(mesh%np)*this%nspin)
455 end if
456
457 call this%accel_copy_pot(mesh)
458
461
462 ! ----------------------------------------------------------------------------------
464 !
465 logical pure function hamiltonian_elec_base_has_magnetic(this) result(has_magnetic)
466 class(hamiltonian_elec_base_t), intent(in) :: this
467
468 has_magnetic = allocated(this%vector_potential) &
469 .or. allocated(this%uniform_magnetic_field) &
470 .or. allocated(this%magnetic_field)
471
473
474 ! ----------------------------------------------------------------------------------
476 !
477 logical pure function hamiltonian_elec_base_has_zeeman(this) result(has_zeeman)
478 class(hamiltonian_elec_base_t), intent(in) :: this
479
480 has_zeeman = allocated(this%zeeman_pot)
481
483
484 ! ----------------------------------------------------------------------------------
486 !
487 logical pure function hamiltonian_elec_base_has_vector_potential(this) result(has_vector_potential)
488 class(hamiltonian_elec_base_t), intent(in) :: this
489
490 has_vector_potential = allocated(this%vector_potential) &
491 .or. allocated(this%uniform_vector_potential)
492
494
495 ! ---------------------------------------------------------------------------------------
496 subroutine hamiltonian_elec_base_rashba(this, mesh, der, std, psib, vpsib)
497 class(hamiltonian_elec_base_t), intent(in) :: this
498 class(mesh_t), intent(in) :: mesh
499 type(derivatives_t), intent(in) :: der
500 type(states_elec_dim_t), intent(in) :: std
501 type(wfs_elec_t), target, intent(in) :: psib
502 type(wfs_elec_t), target, intent(inout) :: vpsib
503
504 integer :: ist, idim, ip
505 complex(real64), allocatable :: psi(:, :), vpsi(:, :), grad(:, :, :)
506
508
509 if (abs(this%rashba_coupling) < m_epsilon) then
511 return
512 end if
513 assert(std%ispin == spinors)
514 assert(mesh%box%dim == 2)
515 assert(psib%type() == type_cmplx)
516 assert(vpsib%type() == type_cmplx)
517
518 safe_allocate(psi(1:mesh%np_part, 1:std%dim))
519 safe_allocate(vpsi(1:mesh%np, 1:std%dim))
520 safe_allocate(grad(1:mesh%np, 1:mesh%box%dim, 1:std%dim))
521
522 do ist = 1, psib%nst
523 call batch_get_state(psib, ist, mesh%np_part, psi)
524 call batch_get_state(vpsib, ist, mesh%np, vpsi)
525
526 do idim = 1, std%dim
527 call zderivatives_grad(der, psi(:, idim), grad(:, :, idim), ghost_update = .false., set_bc = .false.)
528 end do
529
530 if (allocated(this%vector_potential)) then
531 do ip = 1, mesh%np
532 vpsi(ip, 1) = vpsi(ip, 1) - &
533 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), this%vector_potential(1, ip), real64) * psi(ip, 2)
534 vpsi(ip, 2) = vpsi(ip, 2) - &
535 (this%rashba_coupling) * cmplx(this%vector_potential(2, ip), -this%vector_potential(1, ip), real64) * psi(ip, 1)
536 end do
537 end if
538
539 do ip = 1, mesh%np
540 vpsi(ip, 1) = vpsi(ip, 1) - &
541 this%rashba_coupling*( grad(ip, 1, 2) - m_zi*grad(ip, 2, 2))
542 vpsi(ip, 2) = vpsi(ip, 2) + &
543 this%rashba_coupling*( grad(ip, 1, 1) + m_zi*grad(ip, 2, 1))
544 end do
545
546 call batch_set_state(vpsib, ist, mesh%np, vpsi)
547 end do
548
549 safe_deallocate_a(grad)
550 safe_deallocate_a(vpsi)
551 safe_deallocate_a(psi)
552
554 end subroutine hamiltonian_elec_base_rashba
555
556#include "undef.F90"
557#include "real.F90"
558#include "hamiltonian_elec_base_inc.F90"
559
560#include "undef.F90"
561#include "complex.F90"
562#include "hamiltonian_elec_base_inc.F90"
563
565
566!! Local Variables:
567!! mode: f90
568!! coding: utf-8
569!! End:
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:990
subroutine, public accel_detach_buffer(this)
Clear a buffer handle without freeing device memory.
Definition: accel.F90:1059
pure logical function, public accel_is_enabled()
Definition: accel.F90:414
integer, parameter, public accel_mem_read_only
Definition: accel.F90:185
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_epsilon
Definition: global.F90:216
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
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
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:136
The basic Hamiltonian for electronic system.
Describes mesh distribution to nodes.
Definition: mesh.F90:187
int true(void)