Octopus
xc_fbe.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2023 N. Tancogne-Dejean
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module xc_fbe_oct_m
23 use comm_oct_m
24 use debug_oct_m
28 use global_oct_m
29 use grid_oct_m
33 use mesh_oct_m
35 use mpi_oct_m
38 use parser_oct_m
43 use space_oct_m
49
50 implicit none
51
52 private
53 public :: &
54 x_fbe_calc, &
55 lda_c_fbe, &
57
58 type(grid_t), pointer :: gr_aux => null()
59 real(real64), pointer :: rho_aux(:) => null()
60 real(real64), allocatable :: diag_lapl(:)
61
62
63contains
64
65 ! -------------------------------------------------------------------------------------
71 subroutine x_fbe_calc (id, namespace, psolver, gr, st, space, ex, vxc)
72 integer, intent(in) :: id
73 type(namespace_t), intent(in) :: namespace
74 type(poisson_t), intent(in) :: psolver
75 type(grid_t), intent(in) :: gr
76 type(states_elec_t), intent(inout) :: st
77 type(space_t), intent(in) :: space
78 real(real64), intent(inout) :: ex
79 real(real64), contiguous, optional, intent(inout) :: vxc(:,:)
80
81 real(real64), allocatable :: fxc(:,:,:), internal_vxc(:,:)
82
83 push_sub(x_fbe_calc)
84
85 select case(id)
86 case(xc_oep_x_fbe)
87 if (states_are_real(st)) then
88 call dx_fbe_calc(namespace, psolver, gr, gr%der, st, ex, vxc=vxc)
89 else
90 call zx_fbe_calc(namespace, psolver, gr, gr%der, st, ex, vxc=vxc)
91 end if
92 case(xc_oep_x_fbe_sl)
93 safe_allocate(fxc(1:gr%np_part, 1:gr%box%dim, 1:st%d%spin_channels))
94 safe_allocate(internal_vxc(1:gr%np, 1:st%d%spin_channels))
95 internal_vxc = m_zero
96 ! We first compute the force density
97 if (states_are_real(st)) then
98 call dx_fbe_calc(namespace, psolver, gr, gr%der, st, ex, vxc=internal_vxc, fxc=fxc)
99 else
100 call zx_fbe_calc(namespace, psolver, gr, gr%der, st, ex, vxc=internal_vxc, fxc=fxc)
101 end if
102
103 ! We solve the Sturm-Liouville equation
104 if (present(vxc)) then
105 call solve_sturm_liouville(namespace, gr, st, space, fxc, internal_vxc)
106 end if
107
108 ! Get the energy from the virial relation
109 ex = get_virial_energy(gr, st%d%spin_channels, fxc)
110
111 ! Adds the calculated potential
112 call lalg_axpy(gr%np, st%d%spin_channels, m_one, internal_vxc, vxc)
113
114 safe_deallocate_a(fxc)
115 safe_deallocate_a(internal_vxc)
116 case default
117 assert(.false.)
118 end select
119
120 pop_sub(x_fbe_calc)
121 end subroutine x_fbe_calc
122
123 ! -------------------------------------------------------------------------------------
126 subroutine solve_sturm_liouville(namespace, gr, st, space, fxc, vxc)
127 type(namespace_t), intent(in) :: namespace
128 type(grid_t), target, intent(in) :: gr
129 type(states_elec_t), target, intent(in) :: st
130 type(space_t), intent(in) :: space
131 real(real64), contiguous, intent(inout) :: fxc(:,:,:)
132 real(real64), contiguous, intent(inout) :: vxc(:,:)
133
134 real(real64), allocatable :: rhs(:)
135 integer :: iter, ispin
136 real(real64) :: res
137 real(real64), parameter :: threshold = 1e-7_real64
138 character(len=32) :: name
139
140 type(nl_operator_t) :: op(1)
141
142 push_sub(solve_sturm_liouville)
143
144 assert(ubound(fxc, dim=1) >= gr%np_part)
145
146 gr_aux => gr
147 call mesh_init_mesh_aux(gr)
148
149 ! the smoothing is performed uing the same stencil as the Laplacian
150 name = 'FBE preconditioner'
151 call derivatives_get_lapl(gr%der, namespace, op, space, name, 1)
152 safe_allocate(diag_lapl(1:op(1)%np))
153 call dnl_operator_operate_diag(op(1), diag_lapl)
154 call nl_operator_end(op(1))
155
156 safe_allocate(rhs(1:gr%np))
157
158 do ispin = 1, st%d%spin_channels
159 call dderivatives_div(gr%der, fxc(:, :, ispin), rhs)
160 rho_aux => st%rho(:, ispin)
161
162 iter = 500
163 call dqmr_sym_gen_dotu(gr%np, vxc(:, ispin), rhs, &
165 iter, residue = res, threshold = threshold, showprogress = .false.)
166
167 write(message(1), '(a, i6, a)') "Info: Sturm-Liouville solver converged in ", iter, " iterations."
168 write(message(2), '(a, es14.6)') "Info: The residue is ", res
169 call messages_info(2, namespace=namespace)
170 end do
171
172 safe_deallocate_a(rhs)
173
174 safe_deallocate_a(diag_lapl)
175
176 nullify(rho_aux)
177 nullify(gr_aux)
178
179 pop_sub(solve_sturm_liouville)
180 contains
181 !----------------------------------------------------------------
183 subroutine sl_operator(x, hx)
184 real(real64), contiguous, intent(in) :: x(:)
185 real(real64), contiguous, intent(out) :: hx(:)
186
187 integer :: ip, idir
188 real(real64), allocatable :: vxc(:)
189 real(real64), allocatable :: grad_vxc(:,:)
190
191 safe_allocate(vxc(1:gr_aux%np_part))
192 safe_allocate(grad_vxc(1:gr_aux%np_part, 1:gr_aux%box%dim))
193 call lalg_copy(gr_aux%np, x, vxc)
194
195 call dderivatives_grad(gr_aux%der, vxc, grad_vxc)
196
197 !$omp parallel
198 do idir = 1, gr_aux%box%dim
199 !$omp do
200 do ip = 1, gr_aux%np
201 grad_vxc(ip, idir) = grad_vxc(ip, idir)*rho_aux(ip)
202 end do
203 !$omp end do nowait
204 end do
205 !$omp end parallel
206
207 call dderivatives_div(gr_aux%der, grad_vxc, hx)
208
209 safe_deallocate_a(vxc)
210 safe_deallocate_a(grad_vxc)
211 end subroutine sl_operator
212
213 !----------------------------------------------------------------
217 subroutine preconditioner(x, hx)
218 real(real64), contiguous, intent(in) :: x(:)
219 real(real64), contiguous, intent(out) :: hx(:)
220
221 integer :: ip
222
223 !$omp parallel do
224 do ip = 1, gr_aux%np
225 hx(ip) = x(ip) / (max(rho_aux(ip), 1d-12) * diag_lapl(ip))
226 end do
227
228 end subroutine preconditioner
229
230 end subroutine solve_sturm_liouville
231
232 ! -------------------------------------------------------------------------------------
234 real(real64) function get_virial_energy(gr, nspin, fxc) result(exc)
235 type(grid_t), intent(in) :: gr
236 integer, intent(in) :: nspin
237 real(real64), intent(in) :: fxc(:,:,:)
238
239 integer :: isp, idir, ip
240 real(real64), allocatable :: rfxc(:)
241 real(real64) :: xx(gr%box%dim), rr
242
243 push_sub(get_virial_energy)
244
245 exc = m_zero
246 do isp = 1, nspin
247 safe_allocate(rfxc(1:gr%np))
248 do ip = 1, gr%np
249 rfxc(ip) = m_zero
250 call mesh_r(gr, ip, rr, coords=xx)
251 do idir = 1, gr%box%dim
252 rfxc(ip) = rfxc(ip) + fxc(ip, idir, isp) * xx(idir)
253 end do
254 end do
255 exc = exc + dmf_integrate(gr, rfxc)
256 safe_deallocate_a(rfxc)
257 end do
258
259 pop_sub(get_virial_energy)
260 end function get_virial_energy
261
262
263 ! -------------------------------------------------------------------------------------
269 subroutine lda_c_fbe (st, n_blocks, l_dens, l_dedd, l_zk)
270 type(states_elec_t), intent(in) :: st
271 integer, intent(in) :: n_blocks
272 real(real64), intent(in) :: l_dens(:,:)
273 real(real64), intent(inout) :: l_dedd(:,:)
274 real(real64), optional, intent(inout) :: l_zk(:)
275
276 integer :: ip, ispin
277 real(real64) :: rho, beta, beta2, e_c
278 real(real64) :: q
279
280 push_sub(lda_c_fbe)
281
282 ! Set q such that we get the leading order of the r_s->0 limit for the HEG
283 q = ((5.0_real64*sqrt(m_pi)**5)/(m_three*(m_one-log(m_two))))**(m_third)
284 if (present(l_zk)) l_zk = m_zero
285
286 do ip = 1, n_blocks
287 rho = sum(l_dens(1:st%d%spin_channels, ip))
288 if (rho < 1e-20_real64) then
289 l_dedd(1:st%d%spin_channels, ip) = m_zero
290 cycle
291 end if
292 rho = max(rho, 1e-12_real64)
293 beta = q*rho**m_third
294 beta2 = beta**2
295
296 ! Potential
297 ! First part of the potential
298 l_dedd(1:st%d%spin_channels, ip) = (m_pi/(q**3))*((sqrt(m_pi)*beta/(m_one+sqrt(m_pi)*beta))**2 -m_one) * beta
299 ! Second part of the potential
300 l_dedd(1:st%d%spin_channels, ip) = l_dedd(1:st%d%spin_channels, ip) &
301 - (5.0_real64*sqrt(m_pi))/(m_three*q**3)*(log(m_one+sqrt(m_pi)*beta) &
302 -m_half/(m_one+sqrt(m_pi)*beta)**2 + m_two/(m_one+sqrt(m_pi)*beta)) + (5.0_real64*sqrt(m_pi))/(m_two*q**3)
303
304 if (st%d%nspin == 1 .and. present(l_zk)) then
305 ! Energy density
306 ! First part of the energy density
307 e_c = (9.0_real64*q**3)/m_two/beta &
308 - m_two*q**3*sqrt(m_pi) &
309 - 12.0_real64/beta2*(q**3/sqrt(m_pi)) &
310 + m_three/(m_pi*rho)*(m_one/(m_one+sqrt(m_pi)*beta) - m_one &
311 + 5.0_real64*log(m_one+sqrt(m_pi)*beta))
312
313 ! Second part of the energy density
314 e_c = e_c - 5.0_real64/6.0_real64*( &
315 7.0_real64*q**3/beta &
316 + m_three/(m_pi*rho*(m_one+sqrt(m_pi)*beta)) &
317 - 17.0_real64*q**3/sqrt(m_pi)/beta2 &
318 - 11.0_real64*q**3*sqrt(m_pi)/(m_three) &
319 + (20.0_real64/(m_pi*rho) + m_two*sqrt(m_pi)*q**3)*log(m_one+sqrt(m_pi)*beta) &
320 - m_three/(m_pi*rho))
321 e_c = e_c/(q**6)
322 l_zk(ip) = e_c
323 else if(st%d%nspin == 2) then
324 ! Here we have no energy density, so leave the potential unchanged
325 ! This is the approximate potential that we implement here
326 do ispin = 1, st%d%spin_channels
327 l_dedd(ispin, ip) = l_dedd(ispin, ip) * m_two * l_dens(-ispin+3, ip) / rho
328 end do
329 end if
330 end do
331
332 pop_sub(lda_c_fbe)
333 end subroutine lda_c_fbe
334
335 ! -------------------------------------------------------------------------------------
337 subroutine fbe_c_lda_sl (namespace, psolver, gr, st, space, ec, vxc)
338 type(namespace_t), intent(in) :: namespace
339 type(poisson_t), intent(in) :: psolver
340 type(grid_t), intent(in) :: gr
341 type(states_elec_t), intent(inout) :: st
342 type(space_t), intent(in) :: space
343 real(real64), intent(inout) :: ec
344 real(real64), contiguous, optional, intent(inout) :: vxc(:,:)
345
346 integer :: idir, ip, ispin
347 real(real64), allocatable :: fxc(:,:,:), internal_vxc(:,:), grad_rho(:,:,:), tmp1(:,:), tmp2(:,:)
348 real(real64) :: q, beta, rho, l_gdens
349
350 push_sub(fbe_c_lda_sl)
351
352 safe_allocate(internal_vxc(1:gr%np, 1:st%d%spin_channels))
353
354 ! Needed to get the initial guess for the iterative solution of the Sturm-Liouville equation
355 safe_allocate(tmp1(1:st%d%spin_channels, 1:gr%np))
356 safe_allocate(tmp2(1:st%d%spin_channels, 1:gr%np))
357 tmp1 = transpose(st%rho(1:gr%np, 1:st%d%spin_channels))
358 call lda_c_fbe(st, gr%np, tmp1, tmp2)
359 internal_vxc = transpose(tmp2)
360 safe_deallocate_a(tmp1)
361 safe_deallocate_a(tmp2)
363 ! Set q such that we get the leading order of the r_s->0 limit for the HEG
364 q = ((5.0_real64*sqrt(m_pi)**5)/(m_three*(m_one-log(m_two))))**(m_third)
365
366 safe_allocate(fxc(1:gr%np_part, 1:gr%box%dim, 1:st%d%spin_channels))
367 safe_allocate(grad_rho(1:gr%np, 1:gr%box%dim, 1:st%d%spin_channels))
368 do ispin = 1, st%d%spin_channels
369 call dderivatives_grad(gr%der, st%rho(:, ispin), grad_rho(:, :, ispin))
370 end do
371
372 do ispin = 1, st%d%spin_channels
373 do idir = 1, gr%box%dim
374 do ip = 1, gr%np
375 rho = sum(st%rho(ip, 1:st%d%spin_channels))
376 if (st%rho(ip, ispin) < 1e-20_real64) then
377 fxc(ip, idir, ispin) = m_zero
378 cycle
379 end if
380 rho = max(rho, 1e-12_real64)
381 beta = rho**m_third * q
382
383 l_gdens = sum(grad_rho(ip, idir, 1:st%d%spin_channels))
384
385 if (st%d%spin_channels == 1) then
386 fxc(ip, idir, ispin) = l_gdens * &
387 ( m_pi * beta**2/((m_one + sqrt(m_pi)*beta)**2) - m_one &
388 + m_third * m_pi * beta**2 / ((m_one + sqrt(m_pi)*beta)**3) )
389 else
390 fxc(ip, idir, ispin) = m_two * (grad_rho(ip, idir, 3-ispin) * &
391 (m_pi * beta**2/((m_one + sqrt(m_pi)*beta)**2) - m_one ) &
392 + l_gdens * (m_third * m_pi * beta**2 / ((m_one + sqrt(m_pi)*beta)**3) ) &
393 * st%rho(ip, 3-ispin) / rho)
394 end if
395
396 fxc(ip, idir, ispin) = fxc(ip, idir, ispin) * m_pi/(m_three*beta**2) * st%rho(ip, ispin)
397 end do
398 end do
399 end do
400
401 ! We solve the Sturm-Liouville equation
402 if (present(vxc)) then
403 call solve_sturm_liouville(namespace, gr, st, space, fxc, internal_vxc)
404 end if
405
406 ! Get the energy from the virial relation
407 ec = get_virial_energy(gr, st%d%spin_channels, fxc)
408
409 ! Adds the calculated potential
410 call lalg_axpy(gr%np, st%d%spin_channels, m_one, internal_vxc, vxc)
411
412 safe_deallocate_a(fxc)
413
414 pop_sub(fbe_c_lda_sl)
415 end subroutine fbe_c_lda_sl
416
417
418#include "undef.F90"
419#include "real.F90"
420#include "xc_fbe_inc.F90"
421
422#include "undef.F90"
423#include "complex.F90"
424#include "xc_fbe_inc.F90"
425
426end module xc_fbe_oct_m
427
428!! Local Variables:
429!! mode: f90
430!! coding: utf-8
431!! End:
constant times a vector plus a vector
Definition: lalg_basic.F90:170
Copies a vector x, to a vector y.
Definition: lalg_basic.F90:185
double log(double __x) __attribute__((__nothrow__
double sqrt(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 derivatives_get_lapl(this, namespace, op, space, name, order)
subroutine, public dderivatives_div(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the divergence operator to a vector of mesh functions
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_one
Definition: global.F90:188
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module defines various routines, operating on mesh functions.
real(real64) function, public dmf_dotu_aux(f1, f2)
dot product between two vectors (mesh functions) without conjugation
subroutine, public mesh_init_mesh_aux(mesh)
Initialise a pointer to the grid/mesh, that is globally exposed, such that low level mesh operations ...
real(real64) function, public dmf_nrm2_aux(ff)
calculate norm2 of a vector (mesh function)
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_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
This module defines non-local operators.
subroutine, public dnl_operator_operate_diag(op, fo)
subroutine, public nl_operator_end(op)
This module is an helper to perform ring-pattern communications among all states.
This module is intended to contain "only mathematical" functions and procedures.
Definition: solvers.F90:115
subroutine, public dqmr_sym_gen_dotu(np, x, b, op, dotu, nrm2, prec, iter, residue, threshold, showprogress, converged, use_initial_guess)
for complex symmetric matrices W Chen and B Poirier, J Comput Phys 219, 198-209 (2006)
Definition: solvers.F90:1717
pure logical function, public states_are_real(st)
This module handles spin dimensions of the states and the k-point distribution.
subroutine, public lda_c_fbe(st, n_blocks, l_dens, l_dedd, l_zk)
Computes the local density correlation potential and energy obtained from the Colle-Salvetti approxim...
Definition: xc_fbe.F90:363
subroutine solve_sturm_liouville(namespace, gr, st, space, fxc, vxc)
Solve the Sturm-Liouville equation On entry, vxc is the adiabatic one, on exit, it is the solution of...
Definition: xc_fbe.F90:220
subroutine zx_fbe_calc(namespace, psolver, mesh, der, st, ex, vxc, fxc)
Definition: xc_fbe.F90:942
subroutine, public x_fbe_calc(id, namespace, psolver, gr, st, space, ex, vxc)
Interface to X(x_fbe_calc) Two possible run modes possible: adiabatic and Sturm-Liouville....
Definition: xc_fbe.F90:165
subroutine dx_fbe_calc(namespace, psolver, mesh, der, st, ex, vxc, fxc)
Definition: xc_fbe.F90:580
subroutine, public fbe_c_lda_sl(namespace, psolver, gr, st, space, ec, vxc)
Sturm-Liouville version of the FBE local-density correlation functional.
Definition: xc_fbe.F90:431
real(real64) function get_virial_energy(gr, nspin, fxc)
Computes the energy from the force virial relation.
Definition: xc_fbe.F90:328
integer, parameter, public xc_oep_x_fbe_sl
Exchange approximation based on the force balance equation - Sturn-Liouville version.
integer, parameter, public xc_oep_x_fbe
Exchange approximation based on the force balance equation.
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
subroutine sl_operator(x, hx)
Computes Ax = \nabla\cdot(\rho\nabla x)
Definition: xc_fbe.F90:277
subroutine preconditioner(x, hx)
Simple preconditioner Here we need to approximate P^-1 We use the Jacobi approximation and that \nabl...
Definition: xc_fbe.F90:311