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-2024 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 batch_oct_m
25 use comm_oct_m
26 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
35 use math_oct_m
37 use mesh_oct_m
39 use mpi_oct_m
42 use parser_oct_m
47 use space_oct_m
55
56 implicit none
57
58 private
59 public :: &
60 x_fbe_calc, &
61 lda_c_fbe, &
63
64 real(real64), pointer :: rho_aux(:) => null()
65 real(real64), pointer :: lapl_rho_aux(:) => null()
66 real(real64), allocatable :: diag_lapl(:)
67
68
69contains
70
71 ! -------------------------------------------------------------------------------------
77 subroutine x_fbe_calc (id, namespace, psolver, gr, st, space, ex, vxc)
78 integer, intent(in) :: id
79 type(namespace_t), intent(in) :: namespace
80 type(poisson_t), intent(in) :: psolver
81 type(grid_t), target, intent(in) :: gr
82 type(states_elec_t), intent(inout) :: st
83 type(space_t), intent(in) :: space
84 real(real64), intent(inout) :: ex
85 real(real64), contiguous, optional, intent(inout) :: vxc(:,:)
86
87 real(real64), allocatable :: fxc(:,:,:), internal_vxc(:,:)
88
89 push_sub(x_fbe_calc)
90
91 select case(id)
92 case(xc_oep_x_fbe)
93 if (states_are_real(st)) then
94 call dx_fbe_calc(namespace, psolver, gr, st, ex, vxc=vxc)
95 else
96 call zx_fbe_calc(namespace, psolver, gr, st, ex, vxc=vxc)
97 end if
98 case(xc_oep_x_fbe_sl)
99 safe_allocate(fxc(1:gr%np_part, 1:gr%box%dim, 1:st%d%spin_channels))
100 safe_allocate(internal_vxc(1:gr%np, 1:st%d%spin_channels))
101 internal_vxc = m_zero
102 ! We first compute the force density
103 if (states_are_real(st)) then
104 call dx_fbe_calc(namespace, psolver, gr, st, ex, vxc=internal_vxc, fxc=fxc)
105 else
106 call zx_fbe_calc(namespace, psolver, gr, st, ex, vxc=internal_vxc, fxc=fxc)
107 end if
108
109 ! We solve the Sturm-Liouville equation
110 if (present(vxc)) then
111 call solve_sturm_liouville(namespace, gr, st, space, fxc, internal_vxc)
112 end if
113
114 ! Get the energy from the virial relation
115 ex = get_virial_energy(gr, st%d%spin_channels, fxc)
116
117 ! Adds the calculated potential
118 if (present(vxc)) then
119 call lalg_axpy(gr%np, st%d%spin_channels, m_one, internal_vxc, vxc)
120 end if
121
122 safe_deallocate_a(fxc)
123 safe_deallocate_a(internal_vxc)
124 case default
125 assert(.false.)
126 end select
127
128 pop_sub(x_fbe_calc)
129 end subroutine x_fbe_calc
130
131 ! -------------------------------------------------------------------------------------
134 subroutine solve_sturm_liouville(namespace, gr, st, space, fxc, vxc)
135 type(namespace_t), intent(in) :: namespace
136 type(grid_t), target, intent(in) :: gr
137 type(states_elec_t), target, intent(in) :: st
138 type(space_t), intent(in) :: space
139 real(real64), contiguous, intent(inout) :: fxc(:,:,:)
140 real(real64), contiguous, intent(inout) :: vxc(:,:)
141
142 real(real64), allocatable :: rhs(:)
143 integer :: iter, ispin
144 real(real64) :: res
145 real(real64), parameter :: threshold = 1e-7_real64
146 character(len=80) :: name
147
148 type(nl_operator_t) :: op(1)
149
150 push_sub(solve_sturm_liouville)
151
152 assert(ubound(fxc, dim=1) >= gr%np_part)
153
154 call mesh_init_mesh_aux(gr)
155
156 ! the smoothing is performed uing the same stencil as the Laplacian
157 name = 'FBE preconditioner'
158 call derivatives_get_lapl(gr%der, namespace, op, space, name, 1)
159 safe_allocate(diag_lapl(1:op(1)%np))
160 call dnl_operator_operate_diag(op(1), diag_lapl)
161 call nl_operator_end(op(1))
162
163 safe_allocate(rhs(1:gr%np))
164 safe_allocate(lapl_rho_aux(1:gr%np))
165
166 do ispin = 1, st%d%spin_channels
167 call dderivatives_div(gr%der, fxc(:, :, ispin), rhs)
168 rhs=-rhs
169 rho_aux => st%rho(:, ispin)
170 call dderivatives_lapl(gr%der, rho_aux, lapl_rho_aux)
171
172 iter = 500
173 call dqmr_sym_gen_dotu(gr%np, vxc(:, ispin), rhs, &
175 iter, userdata=[c_loc(gr)], residue = res, threshold = threshold, showprogress = .false.)
176
177 write(message(1), '(a, i6, a)') "Info: Sturm-Liouville solver converged in ", iter, " iterations."
178 write(message(2), '(a, es14.6)') "Info: The residue is ", res
179 call messages_info(2, namespace=namespace)
180 end do
181
182 safe_deallocate_p(lapl_rho_aux)
183 safe_deallocate_a(rhs)
184 safe_deallocate_a(diag_lapl)
185
186 nullify(rho_aux)
187
188 pop_sub(solve_sturm_liouville)
189 end subroutine solve_sturm_liouville
190
191 !----------------------------------------------------------------
197 subroutine sl_operator(x, hx, userdata)
198 real(real64), contiguous, intent(in) :: x(:)
199 real(real64), contiguous, intent(out) :: hx(:)
200 type(c_ptr), intent(in) :: userdata(:)
201
202 integer :: ip
203 real(real64), allocatable :: vxc(:)
204 real(real64), allocatable :: prod(:)
205 real(real64), allocatable :: lapl_vxc(:)
206 real(real64), allocatable :: lapl_product(:)
207 type(grid_t), pointer :: gr
208
209 assert(size(userdata) == 1)
210 assert(c_associated(userdata(1)))
211 call c_f_pointer(userdata(1), gr)
212
213 safe_allocate(vxc(1:gr%np_part))
214 safe_allocate(lapl_vxc(1:gr%np))
215 call lalg_copy(gr%np, x, vxc)
216 call dderivatives_lapl(gr%der, vxc, lapl_vxc)
217
218 safe_allocate(prod(1:gr%np_part))
219 safe_allocate(lapl_product(1:gr%np))
220 do ip = 1, gr%np_part
221 prod(ip) = rho_aux(ip) * vxc(ip)
222 end do
223 call dderivatives_lapl(gr%der, prod, lapl_product, set_bc=.false.)
224
225 do ip = 1, gr%np
226 hx(ip) = m_half * (rho_aux(ip) * lapl_vxc(ip) - vxc(ip) * lapl_rho_aux(ip) + lapl_product(ip))
227 end do
228
229 safe_deallocate_a(vxc)
230 safe_deallocate_a(prod)
231 safe_deallocate_a(lapl_vxc)
232 safe_deallocate_a(lapl_product)
233
234 end subroutine sl_operator
235
236 !----------------------------------------------------------------
241 subroutine preconditioner(x, hx, userdata)
242 real(real64), contiguous, intent(in) :: x(:)
243 real(real64), contiguous, intent(out) :: hx(:)
244 type(c_ptr), intent(in) :: userdata(:)
245
246 integer :: ip
247 type(grid_t), pointer :: gr
248
249 assert(size(userdata) == 1)
250 assert(c_associated(userdata(1)))
251 call c_f_pointer(userdata(1), gr)
252
253 !$omp parallel do
254 do ip = 1, gr%np
255 hx(ip) = x(ip) / (max(rho_aux(ip), 1.0e-12_real64) * diag_lapl(ip))
256 end do
257
258 end subroutine preconditioner
259
260 ! -------------------------------------------------------------------------------------
262 real(real64) function get_virial_energy(gr, nspin, fxc) result(exc)
263 type(grid_t), intent(in) :: gr
264 integer, intent(in) :: nspin
265 real(real64), intent(in) :: fxc(:,:,:)
266
267 integer :: isp, idir, ip
268 real(real64), allocatable :: rfxc(:)
269 real(real64) :: xx(gr%box%dim), rr
270
271 push_sub(get_virial_energy)
272
273 exc = m_zero
274 do isp = 1, nspin
275 safe_allocate(rfxc(1:gr%np))
276 do ip = 1, gr%np
277 rfxc(ip) = m_zero
278 call mesh_r(gr, ip, rr, coords=xx)
279 do idir = 1, gr%box%dim
280 rfxc(ip) = rfxc(ip) + fxc(ip, idir, isp) * xx(idir)
281 end do
282 end do
283 exc = exc + dmf_integrate(gr, rfxc)
284 safe_deallocate_a(rfxc)
285 end do
286
287 pop_sub(get_virial_energy)
288 end function get_virial_energy
289
290
291 ! -------------------------------------------------------------------------------------
298 subroutine lda_c_fbe (st, n_blocks, l_dens, l_dedd, l_zk)
299 type(states_elec_t), intent(in) :: st
300 integer, intent(in) :: n_blocks
301 real(real64), intent(in) :: l_dens(:,:)
302 real(real64), intent(inout) :: l_dedd(:,:)
303 real(real64), optional, intent(inout) :: l_zk(:)
304
305 integer :: ip, ispin
306 real(real64) :: rho, beta, beta2, e_c
307 real(real64) :: q
308
309 push_sub(lda_c_fbe)
310
311 ! Set q such that we get the leading order of the r_s->0 limit for the HEG
312 q = ((5.0_real64*sqrt(m_pi)**5)/(m_three*(m_one-log(m_two))))**(m_third)
313 if (present(l_zk)) l_zk = m_zero
314
315 do ip = 1, n_blocks
316 rho = sum(l_dens(1:st%d%spin_channels, ip))
317 if (rho < 1e-20_real64) then
318 l_dedd(1:st%d%spin_channels, ip) = m_zero
319 cycle
320 end if
321 rho = max(rho, 1e-12_real64)
322 beta = q*rho**m_third
323 beta2 = beta**2
324
325 ! Potential
326 ! First part of the potential
327 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
328 ! Second part of the potential
329 l_dedd(1:st%d%spin_channels, ip) = l_dedd(1:st%d%spin_channels, ip) &
330 - (5.0_real64*sqrt(m_pi))/(m_three*q**3)*(log(m_one+sqrt(m_pi)*beta) &
331 -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)
332
333 if (st%d%nspin == 1 .and. present(l_zk)) then
334 ! Energy density
335 ! First part of the energy density
336 e_c = (9.0_real64*q**3)/m_two/beta &
337 - m_two*q**3*sqrt(m_pi) &
338 - 12.0_real64/beta2*(q**3/sqrt(m_pi)) &
339 + m_three/(m_pi*rho)*(m_one/(m_one+sqrt(m_pi)*beta) - m_one &
340 + 5.0_real64*log(m_one+sqrt(m_pi)*beta))
341
342 ! Second part of the energy density
343 e_c = e_c - 5.0_real64/6.0_real64*( &
344 7.0_real64*q**3/beta &
345 + m_three/(m_pi*rho*(m_one+sqrt(m_pi)*beta)) &
346 - 17.0_real64*q**3/sqrt(m_pi)/beta2 &
347 - 11.0_real64*q**3*sqrt(m_pi)/(m_three) &
348 + (20.0_real64/(m_pi*rho) + m_two*sqrt(m_pi)*q**3)*log(m_one+sqrt(m_pi)*beta) &
349 - m_three/(m_pi*rho))
350 e_c = e_c/(q**6)
351 l_zk(ip) = e_c
352 else if(st%d%nspin == 2) then
353 ! Here we have no energy density, so leave the potential unchanged
354 ! This is the approximate potential that we implement here
355 do ispin = 1, st%d%spin_channels
356 l_dedd(ispin, ip) = l_dedd(ispin, ip) * m_two * l_dens(-ispin+3, ip) / rho
357 end do
358 end if
359 end do
360
361 pop_sub(lda_c_fbe)
362 end subroutine lda_c_fbe
363
364 ! -------------------------------------------------------------------------------------
366 subroutine fbe_c_lda_sl (namespace, gr, st, space, ec, vxc)
367 type(namespace_t), intent(in) :: namespace
368 type(grid_t), target, intent(in) :: gr
369 type(states_elec_t), intent(inout) :: st
370 type(space_t), intent(in) :: space
371 real(real64), intent(inout) :: ec
372 real(real64), contiguous, optional, intent(inout) :: vxc(:,:)
373
374 integer :: idir, ip, ispin
375 real(real64), allocatable :: fxc(:,:,:), internal_vxc(:,:), grad_rho(:,:,:), tmp1(:,:), tmp2(:,:)
376 real(real64) :: q, beta, rho, l_gdens
377
378 push_sub(fbe_c_lda_sl)
379
380 safe_allocate(internal_vxc(1:gr%np, 1:st%d%spin_channels))
381
382 ! Needed to get the initial guess for the iterative solution of the Sturm-Liouville equation
383 safe_allocate(tmp1(1:st%d%spin_channels, 1:gr%np))
384 safe_allocate(tmp2(1:st%d%spin_channels, 1:gr%np))
385 tmp1 = transpose(st%rho(1:gr%np, 1:st%d%spin_channels))
386 call lda_c_fbe(st, gr%np, tmp1, tmp2)
387 internal_vxc = transpose(tmp2)
388 safe_deallocate_a(tmp1)
389 safe_deallocate_a(tmp2)
390
391 ! Set q such that we get the leading order of the r_s->0 limit for the HEG
392 q = ((5.0_real64*sqrt(m_pi)**5)/(m_three*(m_one-log(m_two))))**(m_third)
394 safe_allocate(fxc(1:gr%np_part, 1:gr%box%dim, 1:st%d%spin_channels))
395 safe_allocate(grad_rho(1:gr%np, 1:gr%box%dim, 1:st%d%spin_channels))
396 do ispin = 1, st%d%spin_channels
397 call dderivatives_grad(gr%der, st%rho(:, ispin), grad_rho(:, :, ispin))
398 end do
399
400 do ispin = 1, st%d%spin_channels
401 do idir = 1, gr%box%dim
402 do ip = 1, gr%np
403 rho = sum(st%rho(ip, 1:st%d%spin_channels))
404 if (st%rho(ip, ispin) < 1e-20_real64) then
405 fxc(ip, idir, ispin) = m_zero
406 cycle
407 end if
408 rho = max(rho, 1e-12_real64)
409 beta = rho**m_third * q
410
411 l_gdens = sum(grad_rho(ip, idir, 1:st%d%spin_channels))
412
413 if (st%d%spin_channels == 1) then
414 fxc(ip, idir, ispin) = l_gdens * &
415 ( m_pi * beta**2/((m_one + sqrt(m_pi)*beta)**2) - m_one &
416 + m_third * m_pi * beta**2 / ((m_one + sqrt(m_pi)*beta)**3) )
417 else
418 fxc(ip, idir, ispin) = m_two * (grad_rho(ip, idir, 3-ispin) * &
419 (m_pi * beta**2/((m_one + sqrt(m_pi)*beta)**2) - m_one ) &
420 + l_gdens * (m_third * m_pi * beta**2 / ((m_one + sqrt(m_pi)*beta)**3) ) &
421 * st%rho(ip, 3-ispin) / rho)
422 end if
423
424 fxc(ip, idir, ispin) = fxc(ip, idir, ispin) * m_pi/(m_three*beta**2) * st%rho(ip, ispin)
425 end do
426 end do
427 end do
428
429 ! We solve the Sturm-Liouville equation
430 if (present(vxc)) then
431 call solve_sturm_liouville(namespace, gr, st, space, fxc, internal_vxc)
432 end if
433
434 ! Get the energy from the virial relation
435 ec = get_virial_energy(gr, st%d%spin_channels, fxc)
436
437 ! Adds the calculated potential
438 if (present(vxc)) then
439 call lalg_axpy(gr%np, st%d%spin_channels, m_one, internal_vxc, vxc)
440 end if
441
442 safe_deallocate_a(fxc)
443
444 pop_sub(fbe_c_lda_sl)
445 end subroutine fbe_c_lda_sl
446
447#include "undef.F90"
448#include "real.F90"
449#include "xc_fbe_inc.F90"
450
451#include "undef.F90"
452#include "complex.F90"
453#include "xc_fbe_inc.F90"
454
455end module xc_fbe_oct_m
456
457!! Local Variables:
458!! mode: f90
459!! coding: utf-8
460!! End:
constant times a vector plus a vector
Definition: lalg_basic.F90:173
Copies a vector x, to a vector y.
Definition: lalg_basic.F90:188
double log(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
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 calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public derivatives_get_lapl(this, namespace, op, space, name, order)
subroutine, public dderivatives_lapl(der, ff, op_ff, ghost_update, set_bc, factor)
apply the Laplacian to a mesh function
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:200
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements the underlying real-space grid.
Definition: grid.F90:119
Computes and , suitable as an operator callback for iterative solvers (CG, QMR, etc....
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.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)
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:342
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
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:117
subroutine, public dqmr_sym_gen_dotu(np, x, b, op, dotu, nrm2, prec, iter, userdata, 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:1810
pure logical function, public states_are_real(st)
This module provides routines for communicating all batches in a ring-pattern scheme.
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:394
subroutine dx_fbe_calc(namespace, psolver, gr, st, ex, vxc, fxc)
Definition: xc_fbe.F90:611
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:230
subroutine sl_operator(x, hx, userdata)
Computes . This is equivalent to . The last equation is used because it only uses Laplace operators a...
Definition: xc_fbe.F90:293
subroutine zx_fbe_calc(namespace, psolver, gr, st, ex, vxc, fxc)
Definition: xc_fbe.F90:1008
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:173
subroutine, public fbe_c_lda_sl(namespace, gr, st, space, ec, vxc)
Sturm-Liouville version of the FBE local-density correlation functional.
Definition: xc_fbe.F90:462
subroutine preconditioner(x, hx, userdata)
Simple preconditioner Here we need to approximate P^-1 We use the Jacobi approximation and that .
Definition: xc_fbe.F90:337
real(real64) function get_virial_energy(gr, nspin, fxc)
Computes the energy from the force virial relation.
Definition: xc_fbe.F90:358
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:171