Octopus
mxll_elec_coupling.F90
Go to the documentation of this file.
1!! Copyright (C) 2023 F. Bonafé
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#include "global.h"
19
22 use debug_oct_m
24 use global_oct_m
25 use grid_oct_m
27 use, intrinsic :: iso_fortran_env
28 use math_oct_m
29 use mesh_oct_m
32 use parser_oct_m
34 use space_oct_m
37
38 implicit none
39
40 private
41 public :: &
48
49 type :: mxll_coupling_t
50 integer :: coupling_mode
51 integer :: coupling_terms
52 integer :: dipole_field
53 real(real64), allocatable :: e_field(:,:)
54 real(real64), allocatable :: b_field(:,:)
55 real(real64), allocatable :: vec_pot(:,:)
56 real(real64), allocatable :: e_field_dip(:)
57 real(real64), allocatable :: vec_pot_dip(:)
58 real(real64), allocatable :: b_field_dip(:)
59 real(real64), allocatable :: e_quadrupole_pot(:)
60 logical :: calc_field_dip = .false.
61 logical :: add_electric_dip = .false.
62 logical :: add_electric_quad = .false.
63 logical :: add_magnetic_dip = .false.
64 logical :: add_zeeman = .false.
65 logical :: add_non_uniform_vec_pot = .false.
66 real(real64) :: center_of_mass(1:3)
67 integer :: center_of_mass_ip
68 integer :: center_of_mass_rankmin
69 logical :: test_equad = .false.
70 type(derivatives_t), pointer, private :: der
71 real(real64), private :: mass
72 end type mxll_coupling_t
73
74 ! See explanation in the MaxwellCouplingMode variable description.
75 integer, public, parameter :: &
76 NO_MAXWELL_COUPLING = 0, &
81
82 integer, public, parameter :: &
83 DIPOLE_AVERAGE = 0, &
85
86
87contains
88
89 ! ------------------------------------------------------------------------
91 subroutine mxll_coupling_init(this, d, gr, namespace, mass)
92 type(mxll_coupling_t), intent(inout) :: this
93 type(states_elec_dim_t),intent(in) :: d
94 type(grid_t), target, intent(in) :: gr
95 type(namespace_t), intent(in) :: namespace
96 real(real64), intent(in) :: mass
97
98 integer :: terms_default, fmc_default, multipolar_terms, pauli_terms
99
100 push_sub(mxll_coupling_init)
101
102 this%der => gr%der
103 this%mass = mass
104
105 !%Variable MaxwellCouplingMode
106 !%Type integer
107 !%Default none
108 !%Section Hamiltonian
109 !%Description
110 !% This variable selects the level of light-matter coupling with electromagnetic fields from the Maxwell solver.
111 !% Each option defines a coupling Hamiltonian <math> H_{int}</math>.
112 !%Option none 0
113 !% No coupling.
114 !%Option length_gauge_dipole 1
115 !% Dipole level in length gauge with transverse electric field E(t):
116 !% <math> H_{int} = -r.E </math>
117 !% The option MaxwellDipoleField should be set to define if <math>E</math> is calculated as an average at evaluated
118 !% at the center of mass (by default, dipole coupling with the average electric field will be used).
119 !%Option multipolar_expansion 2
120 !% The option MultipoleExpansionTerms selects the terms to be included (electric dipole, electric quadrupole
121 !% and/or magnetic dipole).
122 !%Option velocity_gauge_dipole 3
123 !% Coupling at dipole level in velocity gauge with transverse vector potential A(t).
124 !% <math> H_{int} = 1/2m (2 A(t).p + A^2(t)) </math>
125 !% The option MaxwellDipoleField should be set.
126 !%Option full_minimal_coupling 4
127 !% Full vector potential A(r,t) coupled to the momentum.
128 !% <math> H_{int} = 1/2m (2 A(r,t).p + A^2(r,t)) </math>
129 !%End
130 call parse_variable(namespace, 'MaxwellCouplingMode', no_maxwell_coupling, &
131 this%coupling_mode)
132 this%add_electric_dip = (this%coupling_mode == length_gauge_dipole)
133
134 if (this%coupling_mode == multipolar_expansion) then
135
136 !%Variable MultipolarExpansionTerms
137 !%Type flag
138 !%Default electric_dipole + electric_quadrupole + magnetic_dipole
139 !%Section Hamiltonian
140 !%Description
141 !% Terms to be included in the multipolar expansion.
142 !% For this type of coupling to make sense, the E field has to be calculated at the center of mass (not averaged).
143 !%Option electric_dipole bit(1)
144 !% Adds electric dipole term in length gauge, uses transverse electric field E(t):
145 !% <math> H_{int} = -e (r.E) </math>
146 !%Option electric_quadrupole bit(2)
147 !% Adds electric quadrupole term:
148 !% <math> H_{int} = \frac{1}{2} e (r . Q . r )] <\math>
149 !% where Q is the outer product of gradient and electric field: <math> Q_{ij} = \partial_i E_j |_{r=r_0} </math>
150 !%Option magnetic_dipole bit(3)
151 !% Adds magnetic dipole term:
152 !% <math> H_{int} = - i (e \hbar /2m) \sum_i (\vec{B}(r_0).(\vec{r} x \nabla)) </math>
153 !%End
154 terms_default = &
155 option__multipolarexpansionterms__electric_dipole + &
156 option__multipolarexpansionterms__electric_quadrupole + &
157 option__multipolarexpansionterms__magnetic_dipole
159 call parse_variable(namespace, 'MultipolarExpansionTerms', terms_default, multipolar_terms)
161 if (bitand(multipolar_terms, option__multipolarexpansionterms__electric_dipole) /= 0) then
162 this%add_electric_dip = .true.
163 end if
164 if (bitand(multipolar_terms, option__multipolarexpansionterms__electric_quadrupole) /=0) then
165 this%add_electric_quad = .true.
166 end if
167 if (bitand(multipolar_terms, option__multipolarexpansionterms__magnetic_dipole) /=0) then
168 this%add_magnetic_dip = .true.
169 end if
170
171 end if
172
173 if (this%coupling_mode == full_minimal_coupling) then
174
175 !%Variable PauliHamiltonianTerms
176 !%Type flag
177 !%Default non_uniform_vector_potential + zeeman_term
178 !%Section Hamiltonian
179 !%Description
180 !% Terms to be included in the Pauli Hamiltonnian.
181 !%Option non_uniform_vector_potential bit(1)
182 !% Adds non-uniform vector potential to the canonical momentum.
183 !%Option zeeman_term bit(2)
184 !% Adds the non-uniform Zeeman potential.
185 !%End
186
187 if (d%nspin == 2) then
188 fmc_default = option__paulihamiltonianterms__non_uniform_vector_potential + &
189 option__paulihamiltonianterms__zeeman_term
190 else
191 fmc_default = option__paulihamiltonianterms__non_uniform_vector_potential
192 end if
193
194 call parse_variable(namespace, 'PauliHamiltonianTerms', fmc_default, pauli_terms)
195 if (bitand(pauli_terms, option__paulihamiltonianterms__non_uniform_vector_potential) /= 0) then
196 this%add_non_uniform_vec_pot = .true.
197 end if
198 if (bitand(pauli_terms, option__paulihamiltonianterms__zeeman_term) /=0) then
199 this%add_zeeman = .true.
200 end if
201
202 end if
203
204 !%Variable MaxwellDipoleField
205 !%Type integer
206 !%Default average
207 !%Section Hamiltonian
208 !%Description
209 !% This variable selects the method to get the E field vector at the position of the system
210 !% if Maxwell-matter coupling at dipole level within length gauge is done.
211 !%Option average 0
212 !% Transverse E field is averaged in the volume occupied by the matter system.
213 !%Option center_of_mass 1
214 !% Tranverse E field is evaluated at the center of mass of the matter system (at a single point).
215 !%End
216 call parse_variable(namespace, 'MaxwellDipoleField', dipole_average, &
217 this%dipole_field)
218
219 if (this%coupling_mode /= no_maxwell_coupling) then
220 safe_allocate(this%e_field(1:gr%np, 1:gr%box%dim))
221 safe_allocate(this%b_field(1:gr%np, 1:gr%box%dim))
222 safe_allocate(this%vec_pot(1:gr%np, 1:gr%box%dim))
223 this%e_field = m_zero
224 this%b_field = m_zero
225 this%vec_pot = m_zero
226 safe_allocate(this%e_field_dip(1:gr%box%dim))
227 this%e_field_dip = m_zero
228 safe_allocate(this%b_field_dip(1:gr%box%dim))
229 this%b_field_dip = m_zero
230 safe_allocate(this%vec_pot_dip(1:gr%box%dim))
231 this%vec_pot_dip = m_zero
232 end if
233
234 if (this%coupling_mode == multipolar_expansion .and. this%add_electric_quad) then
235 safe_allocate(this%e_quadrupole_pot(1:gr%np))
236 end if
237
238 call mxll_quadrupole_test_init(this, gr, namespace)
239
240 pop_sub(mxll_coupling_init)
241
242 end subroutine mxll_coupling_init
243
244 ! ------------------------------------------------------------------------
248 subroutine mxll_quadrupole_test_init(this, gr, namespace)
249 type(mxll_coupling_t), intent(inout) :: this
250 type(grid_t), intent(in) :: gr
251 type(namespace_t), intent(in) :: namespace
252
253 integer :: ip, rankmin
254 real(real64) :: dmin
255
257
258 !%Variable MaxwellTestQuadrupole
259 !%Type logical
260 !%Default no
261 !%Section Maxwell
262 !%Description
263 !% Override Maxwell field with linear E field for testing.
264 !%End
265 call parse_variable(namespace, 'MaxwellTestQuadrupole', .false., this%test_equad)
266
267 if (this%test_equad) then
268 safe_allocate(this%e_field(1:gr%np, 1:gr%box%dim))
269 this%e_field = m_zero
270 do ip = 1, gr%np
271 this%e_field(ip,1) = 0.02_real64 * gr%x(ip,1)
272 end do
273 this%calc_field_dip = .true.
274 this%center_of_mass(1:3) = m_zero
275 this%center_of_mass_ip = mesh_nearest_point(gr, this%center_of_mass, dmin, rankmin)
276 this%center_of_mass_rankmin = rankmin
277 safe_allocate(this%e_quadrupole_pot(1:gr%np))
278 end if
279
281
282 end subroutine mxll_quadrupole_test_init
283
284 ! ------------------------------------------------------------------------
286 subroutine mxll_coupling_calc(this, hm_base, mesh, d, space)
287 type(mxll_coupling_t), intent(inout) :: this
288 type(hamiltonian_elec_base_t), intent(inout) :: hm_base
289 type(mesh_t), intent(in) :: mesh
290 type(states_elec_dim_t), intent(in) :: d
291 class(space_t), intent(in) :: space
292
293 integer :: ip, ispin, idir
294
295 push_sub(mxll_coupling_calc)
296
297 ! coupling to Maxwell field
298 select case (this%coupling_mode)
299
301
302 if (this%add_electric_dip) then
303 do ispin = 1, d%spin_channels
304 do ip = 1, mesh%np
305 ! The -1 sign is missing here. Check epot.F90 for the explanation.
306 hm_base%potential(ip, ispin) = hm_base%potential(ip, ispin) + &
307 sum(this%e_field_dip(1:space%dim) * (mesh%x(ip, 1:space%dim) - this%center_of_mass(1:space%dim)))
308 end do
309 end do
310 end if
311
312 if (this%add_electric_quad .and. this%calc_field_dip) then
313 ! the calc_field_dip condition prevents calling the routine before initializing the interactions
314 call set_electric_quadrupole_pot(this, mesh)
315 do ispin = 1, d%spin_channels
316 do ip = 1, mesh%np
317 hm_base%potential(ip, ispin) = hm_base%potential(ip, ispin) + this%e_quadrupole_pot(ip)
318 end do
319 end do
320 end if
321
322 ! magnetic_dipole term is added in hamiltonian_elec_inc.F90
323
325 call hm_base%allocate_field(mesh, field_uniform_vector_potential, .false.)
326 ! The minus sign is here is for the wrong convention of Octopus for the phase
327 hm_base%uniform_vector_potential(1:space%dim) = hm_base%uniform_vector_potential(1:space%dim) - &
328 this%vec_pot_dip(1:space%dim)
329
331 call hm_base%allocate_field(mesh, field_vector_potential, .false.)
332 if (this%add_non_uniform_vec_pot) then
333 do idir = 1, mesh%box%dim
334 hm_base%vector_potential(idir, :) = hm_base%vector_potential(idir, :) + this%vec_pot(:, idir)
335 end do
336 end if
337 if (this%add_zeeman) then
338 call hm_base%allocate_field(mesh, field_magnetic_field, .false.)
339 hm_base%magnetic_field(:,:) = hm_base%magnetic_field(:,:) + this%b_field(:,:)
340 end if
342 end select
343
344 pop_sub(mxll_coupling_calc)
345
346 end subroutine mxll_coupling_calc
347
348 ! ------------------------------------------------------------------------
350 subroutine mxll_coupling_end(this)
351 type(mxll_coupling_t), intent(inout) :: this
352
353 push_sub(mxll_coupling_end)
354
355 safe_deallocate_a(this%e_field)
356 safe_deallocate_a(this%b_field)
357 safe_deallocate_a(this%vec_pot)
358 safe_deallocate_a(this%e_field_dip)
359 safe_deallocate_a(this%b_field_dip)
360 safe_deallocate_a(this%vec_pot_dip)
361 safe_deallocate_a(this%e_quadrupole_pot)
362
363 pop_sub(mxll_coupling_end)
364 end subroutine mxll_coupling_end
365
366
367 ! ------------------------------------------------------------------------
371 subroutine set_electric_quadrupole_pot(this, mesh)
372 type(mxll_coupling_t), intent(inout) :: this
373 type(mesh_t), intent(in) :: mesh
374
375 real(real64), allocatable :: e_field_quadrupole_tensor(:,:), tmp_partial(:,:), this_e_field(:,:)
376 real(real64) :: r(3), tensor_dot_rr(3)
377 integer :: ip, i, dims
378
380
381 call profiling_in('SET_ELECTRIC_QUADRUPOLE')
382
383 safe_allocate(e_field_quadrupole_tensor(1:mesh%box%dim, 1:mesh%box%dim))
384 safe_allocate(this_e_field(1:mesh%np_part, 1:mesh%box%dim))
385 safe_allocate(tmp_partial(1:mesh%np, 1:mesh%box%dim))
386
387 this_e_field(1:mesh%np,:) = this%e_field(1:mesh%np,:)
388
389 e_field_quadrupole_tensor = m_zero
390 dims = this%der%dim
391 do i = 1, dims
392 call dderivatives_grad(this%der, this_e_field(:, i), tmp_partial)
393 if (mesh%mpi_grp%rank == this%center_of_mass_rankmin) then
394 e_field_quadrupole_tensor(i, 1:dims) = tmp_partial(this%center_of_mass_ip, 1:dims)
395 end if
396 end do
397 if (mesh%parallel_in_domains) call mesh%allreduce(e_field_quadrupole_tensor)
398
399 do ip = 1, mesh%np
400 r(:) = mesh%x(ip,:) - this%center_of_mass(:)
401 tensor_dot_rr = matmul(e_field_quadrupole_tensor, r)
402 ! This term is +1/2 r.Q.r and not -1/2 r.Q.r (as e=+1 in Octopus)
403 this%e_quadrupole_pot(ip) = m_half * dot_product(r, tensor_dot_rr)
404 end do
405
406 safe_deallocate_a(e_field_quadrupole_tensor)
407 safe_deallocate_a(tmp_partial)
408 safe_deallocate_a(this_e_field)
409
410 call profiling_out('SET_ELECTRIC_QUADRUPOLE')
412
413 end subroutine set_electric_quadrupole_pot
414
415
416 ! ------------------------------------------------------------------------
421 subroutine magnetic_dipole_coupling(this, psib, hpsib)
422 type(mxll_coupling_t), intent(in) :: this
423 type(wfs_elec_t), intent(inout) :: psib
424 type(wfs_elec_t), intent(inout) :: hpsib
425
426 integer :: ip, idir
427 real(real64) :: rtmp(3)
428 real(real64), allocatable :: bxr(:,:)
429 type(wfs_elec_t) :: gradb(this%der%dim)
430 type(wfs_elec_t) :: bxr_dot_gradb
431
433
434 safe_allocate(bxr(1:this%der%mesh%np,1:3))
435 call profiling_in('MAGNETIC_DIPOLE')
436
437 do ip = 1, this%der%mesh%np
438 rtmp(:) = this%der%mesh%x(ip,:) - this%center_of_mass
439 bxr(ip,:) = dcross_product(this%b_field_dip, rtmp)
440 end do
441
442 call zderivatives_batch_grad(this%der, psib, gradb)
444 call hpsib%copy_to(bxr_dot_gradb)
445 do idir = 1, this%der%dim
446 call batch_mul(this%der%mesh%np, bxr(:,idir), gradb(idir), bxr_dot_gradb)
447 call batch_axpy(this%der%mesh%np, m_zi*m_half/this%mass, bxr_dot_gradb, hpsib)
448 end do
449
450 call bxr_dot_gradb%end()
451 do idir = 1, this%der%dim
452 call gradb(idir)%end()
453 end do
454 safe_deallocate_a(bxr)
455
456 call profiling_out('MAGNETIC_DIPOLE')
458 end subroutine magnetic_dipole_coupling
459
461
462!! Local Variables:
463!! mode: f90
464!! coding: utf-8
465!! End:
batchified version of the BLAS axpy routine:
Definition: batch_ops.F90:152
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public dderivatives_grad(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the gradient to a mesh function
subroutine, public zderivatives_batch_grad(der, ffb, opffb, ghost_update, set_bc, to_cartesian, metric, factor)
apply the gradient to a batch of mesh functions
real(real64), parameter, public m_zero
Definition: global.F90:187
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public m_half
Definition: global.F90:193
This module implements the underlying real-space grid.
Definition: grid.F90:117
integer, parameter, public field_uniform_vector_potential
integer, parameter, public field_vector_potential
integer, parameter, public field_magnetic_field
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
pure real(real64) function, dimension(1:3), public dcross_product(a, b)
Definition: math.F90:1833
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer function, public mesh_nearest_point(mesh, pos, dmin, rankmin)
Returns the index of the point which is nearest to a given vector position pos.
Definition: mesh.F90:380
subroutine, public mxll_coupling_init(this, d, gr, namespace, mass)
Parse variables and initialize Maxwell coupling.
subroutine, public set_electric_quadrupole_pot(this, mesh)
Computes the electric quadrupole potential where .
subroutine mxll_quadrupole_test_init(this, gr, namespace)
Initializes quadrupole test when requested. The test applies an electric field defined as E=(0....
integer, parameter, public length_gauge_dipole
subroutine, public mxll_coupling_end(this)
Finalize and deallocate Maxwell coupling arrays.
subroutine, public mxll_coupling_calc(this, hm_base, mesh, d, space)
Add the Maxwell coupling to the electronic Hamiltonian.
integer, parameter, public velocity_gauge_dipole
integer, parameter, public multipolar_expansion
subroutine, public magnetic_dipole_coupling(this, psib, hpsib)
Computes the magnetic dipole term of the Hamiltonian. This routine acually implements the equivalent...
integer, parameter, public dipole_at_com
integer, parameter, public full_minimal_coupling
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
This module handles spin dimensions of the states and the k-point distribution.
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
The basic Hamiltonian for electronic system.
Describes mesh distribution to nodes.
Definition: mesh.F90:186
class for organizing spins and k-points
batches of electronic states
Definition: wfs_elec.F90:138
int true(void)