Octopus
xc_photons.F90
Go to the documentation of this file.
1!! Copyright (C) 2022 I.-T Lu
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
27
29 use debug_oct_m
31 use epot_oct_m
32 use global_oct_m
33 use grid_oct_m
36 use mesh_oct_m
43 use space_oct_m
45 use parser_oct_m
48
49 implicit none
50
51 private
52 public :: xc_photons_t
53
62 !
63 type xc_photons_t
64 private
65 integer :: method = 0
66 real(real64), allocatable, public :: vpx(:)
67 real(real64), public :: ex
68 type(photon_mode_t) :: pt
69 real(real64) :: pxlda_kappa
70 real(real64) :: eta_c
72 integer :: energy_method = 0
73 logical :: lcorrelations = .false.
74 logical :: llamb_re_mass = .false.
75 logical :: llamb_freespace =.false.
76 real(real64) :: lamb_omega
77
78 logical, public :: lpfmf = .false.
79 real(real64), allocatable, public :: mf_vector_potential(:)
80 real(real64), allocatable :: jp_proj_eo(:,:)
83
84 contains
85 procedure :: init => xc_photons_init
86 procedure :: end => xc_photons_end
87 procedure :: wants_to_renormalize_mass => xc_photons_wants_to_renormalize_mass
88 procedure :: get_renormalized_mass => xc_photons_get_renormalized_emass
89 procedure :: mf_dump => xc_photons_mf_dump
90 procedure :: mf_load => xc_photons_mf_load
91 procedure :: v_ks => xc_photons_v_ks
92 procedure :: add_mean_field => xc_photons_add_mean_field
93 end type xc_photons_t
94
95 ! the PhotonXCXCMethod
96 integer, private, parameter :: &
97 XC_PHOTONS_NONE = 0, &
98 xc_photons_lda = 1, &
100
101contains
102
103 ! ---------------------------------------------------------
105 !
106 subroutine xc_photons_init(xc_photons, namespace, xc_photon, space, gr, st)
107 class(xc_photons_t), intent(out) :: xc_photons
108 type(namespace_t), intent(in) :: namespace
109 integer, intent(in) :: xc_photon
110 class(space_t), intent(in) :: space
111 type(grid_t), intent(in) :: gr
112 type(states_elec_t), intent(in) :: st
113
114 push_sub(xc_photons_init)
115
116 xc_photons%lpfmf = .false.
117
118 call messages_experimental("XCPhotonFunctional /= none")
119
120 call photon_mode_init(xc_photons%pt, namespace, space%dim, .true.)
121 call photon_mode_set_n_electrons(xc_photons%pt, st%qtot)
122
123 select case(xc_photon)
124 case(option__xcphotonfunctional__photon_x_lda)
125 xc_photons%method = xc_photons_lda
126 xc_photons%lcorrelations = .false.
127 case(option__xcphotonfunctional__photon_xc_lda)
128 xc_photons%method = xc_photons_lda
129 xc_photons%lcorrelations = .true.
130 case(option__xcphotonfunctional__photon_x_wfn)
131 xc_photons%method = xc_photons_wfs
132 xc_photons%lcorrelations = .false.
133 case(option__xcphotonfunctional__photon_xc_wfn)
134 xc_photons%method = xc_photons_wfs
135 xc_photons%lcorrelations = .true.
136 case default
137 xc_photons%method = xc_photons_none
138 return
139 end select
140
141
142 if (xc_photons%method == xc_photons_lda) then
143
144 !%Variable PhotonXCLDAKappa
145 !%Type float
146 !%Default 1.0
147 !%Section Hamiltonian::XC
148 !%Description
149 !% the scaling factor for px-LDA potential
150 !%End
151 call parse_variable(namespace, 'PhotonXCLDAKappa', m_one, xc_photons%pxlda_kappa)
152
153 end if
154
155 !%Variable PhotonXCEnergyMethod
156 !%Type integer
157 !%Default 1
158 !%Section Hamiltonian::XC
159 !%Description
160 !% There are different ways to calculate the energy,
161 !%Option virial 1
162 !% (modified) virial approach</br>
163 !% <math>
164 !% (E_{\rm{px}}^{\rm{virial}} = \frac{1}{2}\int d\mathbf{r}\ \mathbf{r}\cdot[
165 !% -\rho(\mathbf{r})\nabla v_{\rm{px}}(\mathbf{r})])
166 !% </math></br>
167 !%Option expectation_value 2
168 !% expectation value w.tr.t. the wave functions (valid only for 1 electron)</br>
169 !% <math>
170 !% E_{\rm{px}}[\rho] = -\sum_{\alpha=1}^{M_{p}}\frac{\tilde{\lambda}_{\alpha}^{2}}{2\tilde{\omega}_{\alpha}^{2}}
171 !% \langle (\tilde{\mathbf{{\varepsilon}}}_{\alpha}\cdot\hat{\mathbf{J}}_{\rm{p}})\Phi[\rho]
172 !% | (\tilde{\mathbf{{\varepsilon}}}_{\alpha}\cdot\hat{\mathbf{J}}_{\rm{p}})\Phi[\rho] \rangle
173 !% </math></br>
174 !% This option only works for the wave function based electron-photon functionals
175 !%Option LDA 3
176 !% energy from electron density</br>
177 !% <math>
178 !% E_{\rm pxLDA}[\rho] = \frac{-2\pi^{2}}{(d+2)({2V_{d}})^{\frac{2}{d}}}
179 !% \sum_{\alpha=1}^{M_{p}}\frac{\tilde{\lambda}_{\alpha}^{2}}{\tilde{\omega}_{\alpha}^{2}}
180 !% \int d\mathbf{r}\ \rho^{\frac{2+d}{d}}(\mathbf{r})
181 !% </math></br>
182 !% This option only works with LDA electron-photon functionals.
183 !%End
185 call parse_variable(namespace, 'PhotonXCEnergyMethod', 1, xc_photons%energy_method)
186
187 if( xc_photons%method == xc_photons_wfs .and. xc_photons%energy_method == option__photonxcenergymethod__lda ) then
188 message(1) = "Calculating the electron-photon energy from the LDA expression"
189 message(2) = "is not implemented for wave function based electron-photon functionals"
190 call messages_fatal(2, namespace=namespace)
191 end if
192
193
194 if (xc_photons%lcorrelations) then
195
196 !%Variable PhotonXCEtaC
197 !%Type float
198 !%Default 1.0
199 !%Section Hamiltonian::XC
200 !%Description
201 !% The scaling factor for the px potential to reduce the weak coupling perturbation regime
202 !%End
203
204 if (parse_is_defined(namespace, 'PhotonXCEtaC')) then
205 call parse_variable(namespace, 'PhotonXCEtaC', m_one, xc_photons%eta_c)
206 else
207 message(1) = "Defining PhotonXCEtaC is required for photon functionals containing correlation."
208 call messages_fatal(1, namespace=namespace)
209 end if
210
211 else
212
213 xc_photons%eta_c = m_one
214
215 end if
216
217 ! This variable will keep vpx across iterations
218 safe_allocate(xc_photons%vpx(1:gr%np_part))
219
220 xc_photons%vpx = m_zero
221
222 !%Variable PhotonXCLambShift
223 !%Type logical
224 !%Default .false.
225 !%Section Hamiltonian::XC
226 !%Description
227 !% to deal with the photon free exchange potential for continuum mode in free space
228 !%End
229
230 call parse_variable(namespace, 'PhotonXCLambShift', .false., xc_photons%llamb_freespace)
231 call messages_experimental("PhotonXCLambShift", namespace=namespace)
232
233 if (xc_photons%llamb_freespace) then
234
235 !%Variable PhotonXCLambShiftOmegaCutoff
236 !%Type float
237 !%Default 0.0
238 !%Section Hamiltonian::XC
239 !%Description
240 !% the cutoff frequency (Ha) for Lamb shift
241 !%End
242
243 call parse_variable(namespace, 'PhotonXCLambShiftOmegaCutoff', m_zero, xc_photons%lamb_omega)
244
245 !%Variable PhotonXCLambShiftRenormalizeMass
246 !%Type logical
247 !%Default .false.
248 !%Section Hamiltonian::XC
249 !%Description
250 !% to deal with the photon free exchange potential for continuum mode in free space
251 !%End
252
253 call parse_variable(namespace, 'PhotonXCLambShiftRenormalizeMass', .false., xc_photons%llamb_re_mass)
254
255 end if
256
257 ! compute the dressed photon modes
258 call photon_mode_dressed(xc_photons%pt)
259
260
261 pop_sub(xc_photons_init)
262
263 end subroutine xc_photons_init
264
265 ! ---------------------------------------------------------
266 subroutine xc_photons_end(this)
267 class(xc_photons_t), intent(inout) :: this
268
269 push_sub(xc_photons_end)
270
271 call photon_mode_end(this%pt)
272 safe_deallocate_a(this%vpx)
273
274 if (allocated(this%mf_vector_potential)) then
275 safe_deallocate_a(this%mf_vector_potential)
276 end if
277 if (allocated(this%jp_proj_eo)) then
278 safe_deallocate_a(this%jp_proj_eo)
279 end if
280
281 pop_sub(xc_photons_end)
282 end subroutine xc_photons_end
283
289 !
290 subroutine xc_photons_v_ks(xc_photons, namespace, total_density, gr, space, psolver, ep, st)
291 class(xc_photons_t), intent(inout) :: xc_photons
292 type(namespace_t), intent(in) :: namespace
293 real(real64), pointer, contiguous, intent(in) :: total_density(:)
294 class(grid_t), intent(in) :: gr
295 type(space_t), intent(in) :: space
296 type(poisson_t), intent(in) :: psolver
297 type(epot_t), intent(in) :: ep
298 type(states_elec_t), intent(inout) :: st
299
300 integer :: ia
301
302 push_sub(xc_photons_v_ks)
303
304 xc_photons%lpfmf = xc_photons%method > 0
305
306 xc_photons%vpx = m_zero
307 xc_photons%ex = m_zero
308
309 if ( .not. allocated(xc_photons%mf_vector_potential) ) then
310 safe_allocate(xc_photons%mf_vector_potential(1:space%dim))
311 xc_photons%mf_vector_potential = m_zero
312 end if
313 if ( .not. allocated(xc_photons%jp_proj_eo)) then
314 safe_allocate(xc_photons%jp_proj_eo(1:xc_photons%pt%nmodes,1:2))
315 xc_photons%jp_proj_eo = m_zero
316 end if
317
318
319 select case(xc_photons%method)
320 case(xc_photons_lda) ! LDA approximation for px potential
321 call photon_free_vpx_lda(namespace, xc_photons, total_density, gr, space, psolver)
322 case(xc_photons_wfs) ! wave function approxmation for px potential
323 call photon_free_vpx_wfc(namespace, xc_photons, total_density, gr, space, st)
324 case(xc_photons_none) ! no photon-exchange potential
325 call messages_write('Photon-free px potential is not computed', new_line = .true.)
326 call messages_info()
327 case default
328 assert(.false.)
329 end select
330
331
332 if (.not. xc_photons%llamb_freespace) then
333 ! add the constant energy shift
334 do ia = 1, xc_photons%pt%nmodes
335 xc_photons%ex = xc_photons%ex + 0.5_real64 * (xc_photons%pt%dressed_omega(ia)-xc_photons%pt%omega(ia))
336 end do
337 end if
338
339 pop_sub(xc_photons_v_ks)
340 end subroutine xc_photons_v_ks
341 ! ---------------------------------------------------------
342
343 ! ---------------------------------------------------------
344 ! ---------------------------------------------------------
345 !
377 ! The Lamb shift code is experimental and untested
378 subroutine photon_free_vpx_lda(namespace, xc_photons, total_density, gr, space, psolver)
379 type(namespace_t), intent(in) :: namespace
380 type(xc_photons_t), intent(inout) :: xc_photons
381 real(real64), pointer, contiguous, intent(in) :: total_density(:)
382 class(grid_t), intent(in) :: gr
383 type(space_t), intent(in) :: space
384 type(poisson_t), intent(in) :: psolver
385
386 integer :: ia, ip, iter
387 real(real64) :: unit_volume, r, res, presum, prefact
388 real(real64) :: xx(space%dim), prefactor_lamb
389 real(real64), allocatable :: prefactor(:)
390 real(real64), allocatable :: rho_aux(:)
391 real(real64), allocatable :: grad_rho_aux(:,:)
392 real(real64), allocatable :: px_source(:)
393 real(real64), allocatable :: tmp1(:)
394 real(real64), allocatable :: tmp2(:,:)
395 real(real64), allocatable :: tmp3(:)
396 real(real64), allocatable :: grad_vpx(:,:)
397 real(real64), allocatable :: epsgrad_epsgrad_rho_aux(:)
398 real(real64), allocatable :: epx_force_module(:)
399
400 real(real64), parameter :: threshold = 1e-7_real64
401
402 push_sub(photon_free_vpx_lda)
403
404 if (xc_photons%energy_method == 2 .and. xc_photons%pt%n_electrons >1) then
405 call messages_not_implemented("expectation value for energy for pxLDA more than 1 electron", namespace=namespace)
406 end if
407
408 xc_photons%vpx = m_zero
409 xc_photons%ex = m_zero
410
411 safe_allocate(prefactor(1:xc_photons%pt%nmodes))
412 prefactor = m_zero
413 ! here we will use only one spin channel
414 safe_allocate(rho_aux(1:gr%np_part))
415 safe_allocate(grad_rho_aux(1:gr%np, 1:xc_photons%pt%dim))
416 safe_allocate(px_source(1:gr%np_part))
417 safe_allocate(tmp1(1:gr%np_part))
418 safe_allocate(tmp2(1:gr%np, 1:xc_photons%pt%dim))
419 safe_allocate(tmp3(1:gr%np_part))
420 safe_allocate(grad_vpx(1:gr%np, 1:xc_photons%pt%dim))
421 grad_vpx = m_zero
422 safe_allocate(epx_force_module(1:gr%np_part))
423 epx_force_module = m_zero
424
425 select case(xc_photons%pt%dim)
426 case(1)
427 unit_volume = m_two
428 case(2)
429 unit_volume = m_pi
430 case(3)
431 unit_volume = m_four*m_pi/m_three
432 case default
433 call messages_not_implemented("LDA px more than 3 dimension", namespace=namespace)
434 end select
435
436 !$omp parallel do
437 do ip=1, gr%np
438 rho_aux(ip) = ( abs(total_density(ip))/(m_two*unit_volume) )**(m_two/(xc_photons%pt%dim*m_one))
439 end do
440 !$omp end parallel do
441
442
443 ! compute the electron-photon exchange potential
444
445 if (xc_photons%llamb_freespace) then
446
447 ! Note: The Lamb shift part is currently experimental and untested!
448 ! compute the electron-photon exchange potential
449
450 prefactor_lamb = -(8.0_real64*m_pi*m_third) * xc_photons%lamb_omega / (p_c**3)
451
452 !$OMP parallel do
453 do ip=1,gr%np
454 xc_photons%vpx(ip) = prefactor_lamb*rho_aux(ip)
455 end do
456 !$OMP end parallel do
457
458 else
459
460 do ia = 1, xc_photons%pt%nmodes
461 prefactor(ia) = -m_two*(m_pi * xc_photons%pt%dressed_lambda(ia) / xc_photons%pt%dressed_omega(ia))**2
462 end do
463
464 select case(xc_photons%pt%dim)
465 case(1)
466 ! solve the pxLDA potential using the analytical form in 1D
467 px_source = m_zero
468 do ia = 1, xc_photons%pt%nmodes
469 !$OMP parallel do
470 do ip=1,gr%np_part
471 px_source(ip) = px_source(ip) + prefactor(ia)
472 end do
473 !$OMP end parallel do
474 end do
475
476 !$OMP parallel do
477 do ip=1,gr%np
478 xc_photons%vpx(ip) = px_source(ip)*rho_aux(ip)
479 end do
480 !$OMP end parallel do
481 case(2)
482 call get_px_source(px_source)
483 ! for 2D we solve the Poisson equation using the conjugate gradient method
484 mesh_aux => gr%der%mesh
485 iter = 1000
486 call dconjugate_gradients(gr%np, xc_photons%vpx(:), px_source, laplacian_op, dmf_dotp_aux, iter, res, threshold)
487 write(message(1),'(a,i6,a)') "Info: CG converged with ", iter, " iterations."
488 write(message(2),'(a,e14.6)') "Info: The residue is ", res
489 call messages_info(2, namespace=namespace)
490
491 case(3)
492 ! for 3D we use thepoisson solver including the prefactor (-4*pi)
493 ! therefore, we need to remove the factor in advance
494 call get_px_source(px_source)
495
496 call lalg_scal(gr%np, m_one/(-m_four*m_pi), px_source)
497
498 ! solve the Poisson equation
499 call dpoisson_solve(psolver, namespace, xc_photons%vpx(:), px_source)
500 case default
501 assert(.false.)
502 end select
503
504 end if
505
506 ! scaling the potential
507 call lalg_scal(gr%np, (xc_photons%eta_c * xc_photons%pxlda_kappa), xc_photons%vpx)
508
509 ! compute electron-photon energy
510
511 select case (xc_photons%energy_method)
512 case(1) ! compute the epx energy from the virial relation
513
514 do ia = 1, xc_photons%pt%nmodes
515
516 ! compute the electron-photon force
517 !$omp parallel do
518 do ip = 1, gr%np
519 epx_force_module(ip) = -prefactor(ia)*m_two*abs(total_density(ip))*rho_aux(ip)/(xc_photons%pt%dim*m_one+m_two)
520 end do
521 !$omp end parallel do
522
523 call dderivatives_grad(gr%der, epx_force_module(:), tmp2)
524 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, tmp2, xc_photons%pt%dressed_pol(1:xc_photons%pt%dim, ia), m_zero, tmp1)
525
526 !$omp parallel do private(r, xx)
527 do ip = 1, gr%np
528 call mesh_r(gr, ip, r, coords=xx)
529 tmp3(ip) = tmp1(ip)*dot_product(xx(1:xc_photons%pt%dim), xc_photons%pt%dressed_pol(1:xc_photons%pt%dim, ia))
530 end do
531 !$omp end parallel do
532
533 xc_photons%ex = xc_photons%ex + m_half*dmf_integrate(gr, tmp3)
534 end do
535
536 xc_photons%ex = xc_photons%eta_c * xc_photons%pxlda_kappa * xc_photons%ex
537
538 case(2) ! compute the energy as expetation value wrt to the wave functions
539
540 rho_aux(1:gr%np) = sqrt(abs( total_density(1:gr%np)))
541
542 safe_allocate(epsgrad_epsgrad_rho_aux(1:gr%np))
543
544 call dderivatives_grad(gr%der, rho_aux(1:gr%np_part), grad_rho_aux)
545
546 do ia = 1, xc_photons%pt%nmodes
547 prefact = (xc_photons%pt%dressed_lambda(ia)**2) / (m_two*xc_photons%pt%dressed_omega(ia)**2)
548
549 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, grad_rho_aux, xc_photons%pt%dressed_pol(:, ia), m_zero, tmp1)
550 call dderivatives_grad(gr%der, tmp1, tmp2)
551 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, tmp2, xc_photons%pt%dressed_pol(1:xc_photons%pt%dim, ia), m_zero, tmp1)
552
553 !$OMP parallel do
554 do ip=1, gr%np
555 epsgrad_epsgrad_rho_aux(ip) = epsgrad_epsgrad_rho_aux(ip) + prefact*tmp1(ip)
556 end do
557 !$OMP end parallel do
558
559 end do
560
561 xc_photons%ex = xc_photons%eta_c * dmf_dotp(gr, rho_aux(1:gr%np), epsgrad_epsgrad_rho_aux(1:gr%np))
562
563 safe_deallocate_a(epsgrad_epsgrad_rho_aux)
564
565 case(3) ! integrate the aux electron density over the volume
566
567 !$OMP parallel do
568 do ip=1,gr%np
569 tmp1(ip) = abs( total_density(ip))**((m_one*xc_photons%pt%dim+m_two)/(xc_photons%pt%dim*m_one))
570 end do
571 !$OMP end parallel do
572
573 ! sum over the prefactors
574 presum = m_zero
575 do ia = 1, xc_photons%pt%nmodes
576 presum = presum + prefactor(ia)
577 end do
578 presum = presum * (m_one/(m_two*unit_volume))**(m_two/(xc_photons%pt%dim*m_one)) / (xc_photons%pt%dim*m_one+m_two)
579 presum = presum * xc_photons%eta_c * xc_photons%pxlda_kappa
580
581 xc_photons%ex = xc_photons%eta_c * xc_photons%pxlda_kappa * presum * dmf_integrate(gr, tmp1)
582
583 end select
584
585 safe_deallocate_a(prefactor)
586 safe_deallocate_a(rho_aux)
587 safe_deallocate_a(grad_rho_aux)
588 safe_deallocate_a(px_source)
589 safe_deallocate_a(tmp1)
590 safe_deallocate_a(tmp2)
591 safe_deallocate_a(tmp3)
592 safe_deallocate_a(grad_vpx)
593 safe_deallocate_a(epx_force_module)
594
595 pop_sub(photon_free_vpx_lda)
596
597 contains
598 ! ---------------------------------------------------------
600 subroutine laplacian_op(x, hx)
601 real(real64), contiguous, intent(in) :: x(:)
602 real(real64), contiguous, intent(out) :: Hx(:)
603
604 real(real64), allocatable :: tmpx(:)
605
606 safe_allocate(tmpx(1:gr%np_part))
607 call lalg_copy(gr%np, x, tmpx)
608 call dderivatives_lapl(gr%der, tmpx, hx)
609 safe_deallocate_a(tmpx)
610
611 end subroutine laplacian_op
612
613 subroutine get_px_source(px_source)
614 real(real64), contiguous, intent(out) :: px_source(:)
615
616 call dderivatives_grad(gr%der, rho_aux(1:gr%np_part), grad_rho_aux)
617
618 px_source = m_zero
619 do ia = 1, xc_photons%pt%nmodes
620 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, grad_rho_aux, xc_photons%pt%dressed_pol(:, ia), m_zero, tmp1)
621 call dderivatives_grad(gr%der, tmp1, tmp2)
622 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, tmp2, xc_photons%pt%dressed_pol(1:xc_photons%pt%dim, ia), m_zero, tmp1)
623 call lalg_axpy(gr%np, prefactor(ia), tmp1, px_source)
624 end do
625
626 end subroutine get_px_source
627
628 end subroutine photon_free_vpx_lda
629 ! ---------------------------------------------------------
630
631 ! ---------------------------------------------------------
632 !
658 !
659 ! The Lamb shift code is experimental and untested
660
661 subroutine photon_free_vpx_wfc(namespace, xc_photons, total_density, gr, space, st)
662 type(namespace_t), intent(in) :: namespace
663 type(xc_photons_t), intent(inout) :: xc_photons
664 real(real64), pointer, contiguous, intent(in) :: total_density(:)
665 class(grid_t), intent(in) :: gr
666 type(space_t), intent(in) :: space
667 type(states_elec_t), intent(in) :: st
668
669 integer :: ia, ip
670 real(real64) :: prefactor_lamb
671 real(real64) :: xx(space%dim), r
672 real(real64), allocatable :: prefactor(:)
673 real(real64), allocatable :: rho_aux(:)
674 real(real64), allocatable :: grad_rho_aux(:,:)
675 real(real64), allocatable :: grad_vpx(:,:)
676 real(real64), allocatable :: epsgrad_epsgrad_rho_aux(:)
677 real(real64), allocatable :: tmp1(:)
678 real(real64), allocatable :: tmp2(:,:)
679 real(real64) :: shift
680
681 push_sub(photon_free_vpx_wfc)
682
683 if (st%d%nspin >1) then
684 call messages_not_implemented("PhotonXCXCMethod = wavefunction for polarized and spinor cases", namespace=namespace)
685 end if
686
687 if (xc_photons%pt%n_electrons >1) then
688 call messages_not_implemented("PhotonXCXCMethod = wavefunction for more than 1 electron", namespace=namespace)
689 end if
690
691 xc_photons%vpx = m_zero
692 xc_photons%ex = m_zero
694 safe_allocate(prefactor(1:xc_photons%pt%nmodes))
695 prefactor = m_zero
696 safe_allocate(rho_aux(1:gr%np_part))
697 rho_aux = m_zero
698 safe_allocate(grad_rho_aux(1:gr%np, 1:xc_photons%pt%dim))
699 grad_rho_aux = m_zero
700 safe_allocate(epsgrad_epsgrad_rho_aux(1:gr%np))
701 safe_allocate(grad_vpx(1:gr%np, 1:xc_photons%pt%dim))
702 safe_allocate(tmp1(1:gr%np_part))
703 safe_allocate(tmp2(1:gr%np_part, 1:xc_photons%pt%dim))
704
705
706 rho_aux(1:gr%np) = sqrt(abs( total_density(1:gr%np)))
707 !$OMP parallel do
708 do ip = 1, gr%np
709 rho_aux(ip) = safe_tol(rho_aux(ip),1e-18_real64)
710 end do
711 !$OMP end parallel do
712
713 if (xc_photons%llamb_freespace) then
714
715 ! experimental Lamb shift mode
716
717 prefactor_lamb = ( m_two/(m_three*m_pi) ) * xc_photons%lamb_omega / p_c**3
718 call dderivatives_lapl(gr%der, rho_aux(1:gr%np_part), epsgrad_epsgrad_rho_aux)
719 call lalg_scal(gr%np, prefactor_lamb, epsgrad_epsgrad_rho_aux)
720
721 else
722
723 do ia = 1, xc_photons%pt%nmodes
724 prefactor(ia) = (xc_photons%pt%dressed_lambda(ia)**2) / (m_two*xc_photons%pt%dressed_omega(ia)**2)
725 end do
726
727 call dderivatives_grad(gr%der, rho_aux, grad_rho_aux)
728
729 epsgrad_epsgrad_rho_aux = m_zero
730 do ia = 1, xc_photons%pt%nmodes
731 tmp1 = m_zero
732 call lalg_gemv(gr%np, xc_photons%pt%dim, m_one, grad_rho_aux, xc_photons%pt%dressed_pol(:, ia), m_zero, tmp1)
733 call dderivatives_grad(gr%der, tmp1, tmp2)
734 call lalg_gemv(gr%np, xc_photons%pt%dim, prefactor(ia), tmp2, xc_photons%pt%dressed_pol(:, ia), &
735 m_one, epsgrad_epsgrad_rho_aux)
736 end do
737
738 end if
739
740 !$OMP parallel do
741 do ip = 1, gr%np
742 xc_photons%vpx(ip) = epsgrad_epsgrad_rho_aux(ip)/rho_aux(ip)
743 end do
744 !$OMP end parallel do
745
746 if(st%eigenval(1,1) < m_huge .and. .not. space%is_periodic()) then
747 shift = m_two * st%eigenval(1,1) * prefactor(1)
748 !$OMP parallel do
749 do ip=1, gr%np
750 xc_photons%vpx(ip) = xc_photons%vpx(ip) + shift
751 end do
752 !$OMP end parallel do
753 end if
755 call lalg_scal(gr%np, xc_photons%eta_c, xc_photons%vpx(:))
756
757 select case (xc_photons%energy_method)
758 case(1) ! virial
759
760 call dderivatives_grad(gr%der, xc_photons%vpx(:), grad_vpx)
761 !$OMP parallel do private(r, xx)
762 do ip = 1, gr%np
763 call mesh_r(gr, ip, r, coords=xx)
764 tmp1(ip) = - total_density(ip)*dot_product(xx(1:xc_photons%pt%dim), grad_vpx(ip,1:xc_photons%pt%dim))
765 end do
766 !$OMP end parallel do
767
768 xc_photons%ex = m_half*dmf_integrate(gr, tmp1)
769
770 case(2) ! expectation_value
771 xc_photons%ex = xc_photons%eta_c * dmf_dotp(gr, rho_aux(1:gr%np), epsgrad_epsgrad_rho_aux)
772
773 case default
774 assert(.false.)
775 end select
776
777 safe_deallocate_a(prefactor)
778 safe_deallocate_a(rho_aux)
779 safe_deallocate_a(grad_rho_aux)
780 safe_deallocate_a(grad_vpx)
781 safe_deallocate_a(epsgrad_epsgrad_rho_aux)
782 safe_deallocate_a(tmp1)
783 safe_deallocate_a(tmp2)
784
785 pop_sub(photon_free_vpx_wfc)
786
787 end subroutine photon_free_vpx_wfc
788 ! ---------------------------------------------------------
789
790
791 ! ---------------------------------------------------------
801 !
802 subroutine xc_photons_add_mean_field(xc_photons, gr, space, kpoints, st, time, dt)
803 class(xc_photons_t), intent(inout) :: xc_photons
804 class(grid_t), intent(in) :: gr
805 class(space_t), intent(in) :: space
806 type(kpoints_t), intent(in) :: kpoints
807 type(states_elec_t), intent(inout) :: st
808 real(real64), intent(in) :: time
809 real(real64), intent(in) :: dt
810
811
812 integer :: ia, idir, ispin
813 real(real64) :: pol_dot_jp
814 real(real64), allocatable :: current(:,:,:)
815 real(real64), allocatable :: jp(:)
816
818
819 ! compute the dressed photon-free vector potential
820 xc_photons%mf_vector_potential = m_zero
821
822 safe_allocate(current(1:gr%np_part, 1:space%dim, 1:st%d%nspin))
823 current = m_zero
824 ! here we use the paramagnetic current; note that the physical current here
825 ! only contains the paramagnetic current.
826 call states_elec_calc_quantities(gr, st, kpoints, .false., paramagnetic_current = current)
827
828 ! compute the paramagnetic current
829 safe_allocate(jp(1:space%dim))
830 do idir = 1, space%dim
831 jp(idir) = m_zero
832 do ispin = 1, st%d%spin_channels
833 jp(idir) = jp(idir) + dmf_integrate(gr%der%mesh, current(:,idir,ispin))
834 end do
835 end do
836
837 ! update the 'projected' current
838 do ia = 1, xc_photons%pt%nmodes
839 pol_dot_jp = dot_product(xc_photons%pt%dressed_pol(1:space%dim, ia),jp(1:space%dim))
840 xc_photons%jp_proj_eo(ia,1) = xc_photons%jp_proj_eo(ia,1) + &
841 cos(xc_photons%pt%dressed_omega(ia)*( time-dt))*pol_dot_jp*dt
842 xc_photons%jp_proj_eo(ia,2) = xc_photons%jp_proj_eo(ia,2) + &
843 sin(xc_photons%pt%dressed_omega(ia)*( time-dt))*pol_dot_jp*dt
844 end do
845
846 do ia = 1, xc_photons%pt%nmodes
847 xc_photons%mf_vector_potential(1:xc_photons%pt%dim) = xc_photons%mf_vector_potential(1:xc_photons%pt%dim) &
848 + (-p_c*(xc_photons%pt%dressed_lambda(ia)**2) / xc_photons%pt%dressed_omega(ia)) &
849 * (xc_photons%jp_proj_eo(ia,1)*sin(xc_photons%pt%dressed_omega(ia)* time) &
850 - xc_photons%jp_proj_eo(ia,2)*cos(xc_photons%pt%dressed_omega(ia)* time)) &
851 * xc_photons%pt%dressed_pol(1:xc_photons%pt%dim, ia)
852 end do
853
854 safe_deallocate_a(current)
855 safe_deallocate_a(jp)
856
858
859 end subroutine xc_photons_add_mean_field
860 ! ---------------------------------------------------------
861
862
866 !
867 logical pure function xc_photons_wants_to_renormalize_mass(xc_photons) result (renorm)
868 class(xc_photons_t), intent(in) :: xc_photons
869
870 renorm = (xc_photons%method>0) .and. xc_photons%llamb_freespace .and. xc_photons%llamb_re_mass
871
873
875 real(real64) pure function xc_photons_get_renormalized_emass(xc_photons) result(mass)
876 class(xc_photons_t), intent(in) :: xc_photons
877
878 mass = m_one - (m_four*xc_photons%lamb_omega) / (3.0*m_pi * p_c**3)
879
881
883 !
884 subroutine xc_photons_mf_dump(xc_photons, restart, ierr)
885 class(xc_photons_t), intent(in) :: xc_photons
886 type(restart_t), intent(in) :: restart
887 integer, intent(out) :: ierr
888
889 character(len=80), allocatable :: lines(:)
890 integer :: iunit, err, jj, nmodes
891 integer :: pt_dim
892
893 push_sub(photon_free_mf_dump)
894 nmodes = xc_photons%pt%nmodes
895 pt_dim = xc_photons%pt%dim
896
897 safe_allocate(lines(1:nmodes+pt_dim))
898
899 ierr = 0
900
901 iunit = restart_open(restart, 'photon_free_mf')
902
903 do jj = 1, pt_dim
904 write(lines(jj), '(2x, es19.12)') xc_photons%mf_vector_potential(jj)
905 end do
906
907 do jj = 1, nmodes
908 write(lines(jj+pt_dim), '(a10,1x,I8,a1,2x,2(es19.12,2x))') 'Mode ', jj, ":", xc_photons%jp_proj_eo(jj,1:2)
909 end do
910
911 call restart_write(restart, iunit, lines, nmodes+pt_dim, err)
912 if (err /= 0) ierr = ierr + 1
913 call restart_close(restart, iunit)
914
915 safe_deallocate_a(lines)
916
917 pop_sub(photon_free_mf_dump)
918 end subroutine xc_photons_mf_dump
919
920! ---------------------------------------------------------
921
923 !
924 subroutine xc_photons_mf_load(xc_photons, restart, space, ierr)
925 class(xc_photons_t), intent(inout) :: xc_photons
926 type(restart_t), intent(in) :: restart
927 class(space_t), intent(in) :: space
928 integer, intent(out) :: ierr
929
930 character(len=80), allocatable :: lines(:)
931 character(len=7) :: sdummy
932 integer :: idummy
933 integer :: iunit, err, jj, nmodes
934 integer :: pt_dim
935
936 push_sub(photon_free_mf_load)
937
938 ierr = 0
939 nmodes = xc_photons%pt%nmodes
940 pt_dim = xc_photons%pt%dim
941
942 if (restart_skip(restart)) then
943 ierr = -1
944 pop_sub(photon_free_mf_load)
945 return
946 end if
947
948 message(1) = "Debug: Reading Photon-Free Photons restart."
949 call messages_info(1, namespace=restart%namespace, debug_only=.true.)
950
951 if ( .not. allocated(xc_photons%jp_proj_eo)) then
952 safe_allocate(xc_photons%jp_proj_eo(1:xc_photons%pt%nmodes, 1:2))
953 xc_photons%jp_proj_eo = m_zero
954 end if
955 if ( .not. allocated(xc_photons%mf_vector_potential)) then
956 safe_allocate(xc_photons%mf_vector_potential(1:space%dim))
957 xc_photons%mf_vector_potential = m_zero
958 end if
959
960 safe_allocate(lines(1:nmodes+pt_dim))
961 iunit = restart_open(restart, 'photon_free_mf')
962 call restart_read(restart, iunit, lines, nmodes+pt_dim, err)
963 if (err /= 0) then
964 ierr = ierr + 1
965 else
966 do jj = 1, pt_dim
967 read(lines(jj),'(2x, es19.12)') xc_photons%mf_vector_potential(jj)
968 end do
969
970 do jj = 1, nmodes
971 read(lines(jj+pt_dim), '(a10,1x,I8,a1,2x,2(es19.12,2x))') sdummy, idummy, sdummy, xc_photons%jp_proj_eo(jj,1:2)
972 end do
973 end if
974 call restart_close(restart, iunit)
975
976 message(1) = "Debug: Reading Photons restart done."
977 call messages_info(1, namespace=restart%namespace, debug_only=.true.)
978
979 safe_deallocate_a(lines)
980
981 pop_sub(photon_free_mf_load)
982 end subroutine xc_photons_mf_load
983
984end module xc_photons_oct_m
985
986!! Local Variables:
987!! mode: f90
988!! coding: utf-8
989!! End:
constant times a vector plus a vector
Definition: lalg_basic.F90:171
Copies a vector x, to a vector y.
Definition: lalg_basic.F90:186
scales a vector by a constant
Definition: lalg_basic.F90:157
double sin(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
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 dderivatives_lapl(der, ff, op_ff, ghost_update, set_bc, factor)
apply the Laplacian to a mesh function
real(real64), parameter, public m_two
Definition: global.F90:190
real(real64), parameter, public m_huge
Definition: global.F90:206
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_four
Definition: global.F90:192
real(real64), parameter, public m_third
Definition: global.F90:195
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
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
real(real64), parameter, public m_one
Definition: global.F90:189
real(real64), parameter, public m_three
Definition: global.F90:191
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module defines various routines, operating on mesh functions.
class(mesh_t), pointer, public mesh_aux
Globally-scoped pointer to the mesh instance.
real(real64) function, public dmf_dotp_aux(f1, f2)
dot product between two vectors (mesh functions)
real(real64) function, public dmf_integrate(mesh, ff, mask, reduce)
Integrate a function on the mesh.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:336
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1113
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:414
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1085
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
subroutine, public photon_mode_end(this)
subroutine, public photon_mode_dressed(this)
subroutine, public photon_mode_set_n_electrons(this, qtot)
subroutine, public photon_mode_init(this, namespace, dim, photon_free)
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:892
This module is intended to contain "only mathematical" functions and procedures.
Definition: solvers.F90:115
subroutine, public states_elec_calc_quantities(gr, st, kpoints, nlcc, kinetic_energy_density, paramagnetic_current, density_gradient, density_laplacian, gi_kinetic_energy_density, st_end)
calculated selected quantities
This module implements the "photon-free" electron-photon exchange-correlation functional.
Definition: xc_photons.F90:121
subroutine photon_free_vpx_wfc(namespace, xc_photons, total_density, gr, space, st)
compute the electron-photon exchange potential based on wave functions
Definition: xc_photons.F90:755
logical pure function xc_photons_wants_to_renormalize_mass(xc_photons)
indicate whether the photon-exchange requires a renormalized electron mass
Definition: xc_photons.F90:961
subroutine xc_photons_init(xc_photons, namespace, xc_photon, space, gr, st)
initialize the photon-exchange functional
Definition: xc_photons.F90:200
subroutine xc_photons_add_mean_field(xc_photons, gr, space, kpoints, st, time, dt)
accumulate the results of time integral the paramagnetic current.
Definition: xc_photons.F90:896
subroutine xc_photons_mf_dump(xc_photons, restart, ierr)
write restart information
Definition: xc_photons.F90:978
subroutine xc_photons_v_ks(xc_photons, namespace, total_density, gr, space, psolver, ep, st)
evaluate the KS potential and energy for the given functional
Definition: xc_photons.F90:384
real(real64) pure function xc_photons_get_renormalized_emass(xc_photons)
return the renormalized electron mass for the electron-photon exhange
Definition: xc_photons.F90:969
integer, parameter, private xc_photons_lda
Definition: xc_photons.F90:189
subroutine photon_free_vpx_lda(namespace, xc_photons, total_density, gr, space, psolver)
compute the electron-photon exchange potential within the LDA
Definition: xc_photons.F90:472
subroutine xc_photons_end(this)
Definition: xc_photons.F90:360
integer, parameter, private xc_photons_wfs
Definition: xc_photons.F90:189
subroutine xc_photons_mf_load(xc_photons, restart, space, ierr)
load restart information
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
The states_elec_t class contains all electronic wave functions.
This class described the 'photon-exchange' electron-photon xc functionals, based on QEDFT.
Definition: xc_photons.F90:156
int true(void)
subroutine laplacian_op(x, hx)
Computes .
Definition: test.F90:477
subroutine get_px_source(px_source)
Definition: xc_photons.F90:707