28 use,
intrinsic :: iso_fortran_env
55 integer,
public,
parameter :: &
56 POISSON_FFT_KERNEL_NONE = -1, &
66 type(fourier_space_op_t) :: coulb
68 real(real64) :: soft_coulb_param
71 real(real64),
parameter :: TOL_VANISHING_Q = 1e-6_real64
74 subroutine poisson_fft_init(this, namespace, space, cube, kernel, soft_coulb_param, fullcube)
75 type(poisson_fft_t),
intent(out) :: this
76 type(namespace_t),
intent(in) :: namespace
77 class(space_t),
intent(in) :: space
78 type(cube_t),
intent(inout) :: cube
79 integer,
intent(in) :: kernel
80 real(real64),
optional,
intent(in) :: soft_coulb_param
81 type(cube_t),
optional,
intent(in) :: fullcube
88 safe_allocate(this%coulb%qq(1:space%dim))
89 this%coulb%qq(1:space%periodic_dim) =
m_zero
90 this%coulb%qq(space%periodic_dim+1:space%dim) = 1e-5_real64
91 this%coulb%singularity =
m_zero
102 type(namespace_t),
intent(in) :: namespace
103 class(space_t),
intent(in) :: space
104 type(cube_t),
intent(in) :: cube
105 type(fourier_space_op_t),
intent(inout) :: coulb
106 integer,
intent(in) :: kernel
107 real(real64),
optional,
intent(in) :: soft_coulb_param
108 type(cube_t),
optional,
intent(in) :: fullcube
114 message(1) =
"The screened Coulomb potential is only implemented in 3D for PoissonFFTKernel=fft_nocut."
121 if (.not.
present(fullcube))
then
122 message(1) =
"Hockney's FFT-kernel needs cube of full unit cell "
125 if (.not.
allocated(fullcube%fft))
then
126 message(1) =
"Hockney's FFT-kernel needs PoissonSolver=fft"
133 select case (space%dim)
135 assert(
present(soft_coulb_param))
142 message(1) =
"Invalid Poisson FFT kernel for 1D."
155 message(1) =
"Invalid Poisson FFT kernel for 2D."
177 message(1) =
"Invalid Poisson FFT kernel for 3D."
187 subroutine get_cutoff(namespace, default_r_c, r_c)
189 real(real64),
intent(in) :: default_r_c
190 real(real64),
intent(out) :: r_c
201 call messages_write(
'Poisson cutoff radius is larger than cell size.', new_line = .
true.)
202 call messages_write(
'You can see electrons in neighboring cell(s).')
211 type(
cube_t),
intent(in) :: cube
214 integer :: ix, iy, iz, ixx(3), db(3), n1, n2, n3, lx, ly, lz
215 real(real64) :: temp(3), modg2, inv_four_mu2, ecut
216 real(real64) :: gg(3)
217 real(real64),
allocatable :: fft_coulb_fs(:,:,:)
221 db(1:3) = cube%rs_n_global(1:3)
229 n1 = max(1, cube%fs_n(1))
230 n2 = max(1, cube%fs_n(2))
231 n3 = max(1, cube%fs_n(3))
234 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
237 temp(1:3) =
m_two*
m_pi/(db(1:3)*cube%spacing(1:3))
242 ix = cube%fs_istart(1) + lx - 1
245 iy = cube%fs_istart(2) + ly - 1
248 iz = cube%fs_istart(3) + lz - 1
253 if(modg2 >
m_two*ecut*1.001_real64) cycle
256 if (cube%fft%library.eq.
fftlib_nfft) modg2=cube%Lfs(ix,1)**2+cube%Lfs(iy,2)**2+cube%Lfs(iz,3)**2
258 if (modg2 > tol_vanishing_q)
then
262 fft_coulb_fs(lx, ly, lz) =
m_four*
m_pi/modg2*(coulb%alpha + coulb%beta*
exp(-modg2*inv_four_mu2))
264 fft_coulb_fs(lx, ly, lz) =
m_four*
m_pi/modg2*coulb%beta*(
m_one-
exp(-modg2*inv_four_mu2))
268 fft_coulb_fs(lx, ly, lz) =
m_four*
m_pi/modg2*coulb%alpha
277 fft_coulb_fs(lx, ly, lz) =
m_four*
m_pi*inv_four_mu2 * coulb%beta
281 fft_coulb_fs(lx, ly, lz) = coulb%singularity*coulb%alpha +
m_four*
m_pi*inv_four_mu2 * coulb%beta
283 fft_coulb_fs(lx, ly, lz) = coulb%singularity
296 safe_deallocate_a(fft_coulb_fs)
307 type(
cube_t),
intent(in) :: cube
309 type(
cube_t),
intent(in) :: fullcube
311 integer :: ix, iy, iz, ixx(3), db(3), nfs(3), nrs(3), nfs_s(3), nrs_s(3)
312 real(real64) :: temp(3), modg2, weight
313 real(real64) :: gg(3)
314 real(real64),
allocatable :: fft_Coulb_small_RS(:,:,:)
315 real(real64),
allocatable :: fft_Coulb_RS(:,:,:)
316 complex(real64),
allocatable :: fft_Coulb_small_FS(:,:,:), fft_Coulb_FS(:,:,:)
323 nfs(1:3) = fullcube%fs_n_global(1:3)
324 nrs(1:3) = fullcube%rs_n_global(1:3)
326 safe_allocate(fft_coulb_fs(1:nfs(1),1:nfs(2),1:nfs(3)))
327 safe_allocate(fft_coulb_rs(1:nrs(1),1:nrs(2),1:nrs(3)))
330 nfs_s(1:3) = cube%fs_n_global(1:3)
331 nrs_s(1:3) = cube%rs_n_global(1:3)
333 safe_allocate(fft_coulb_small_fs(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3)))
334 safe_allocate(fft_coulb_small_rs(1:nrs_s(1),1:nrs_s(2),1:nrs_s(3)))
339 db(1:3) = fullcube%rs_n_global(1:3)
340 temp(1:3) =
m_two*
m_pi/(db(1:3)*cube%spacing(1:3))
351 if (abs(modg2) > tol_vanishing_q)
then
352 fft_coulb_fs(ix, iy, iz) =
m_one/modg2
354 fft_coulb_fs(ix, iy, iz) =
m_zero
362 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
367 fft_coulb_fs(ix, iy, iz) = weight*fft_coulb_fs(ix, iy, iz)
379 if (ix.le.nrs_s(1)/2+1)
then
382 ixx(1) = nrs(1) - nrs_s(1)+ix
385 if (iy.le.nrs_s(2)/2+1)
then
388 ixx(2) = nrs(2) - nrs_s(2)+iy
391 if (iz.le.nrs_s(3)/2+1)
then
394 ixx(3) = nrs(3) - nrs_s(3)+iz
396 fft_coulb_small_rs(ix,iy,iz) = fft_coulb_rs(ixx(1),ixx(2),ixx(3))
401 call dfft_forward(cube%fft, fft_coulb_small_rs, fft_coulb_small_fs)
403 fft_coulb_small_rs(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3)) = &
404 real( fft_Coulb_small_FS(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3)), real64)
410 fft_coulb_small_rs(cube%fs_istart(1):cube%fs_istart(1)+cube%fs_n(1), &
411 cube%fs_istart(2):cube%fs_istart(2)+cube%fs_n(2), &
412 cube%fs_istart(3):cube%fs_istart(3)+cube%fs_n(3)))
414 safe_deallocate_a(fft_coulb_fs)
415 safe_deallocate_a(fft_coulb_rs)
416 safe_deallocate_a(fft_coulb_small_fs)
417 safe_deallocate_a(fft_coulb_small_rs)
427 type(
cube_t),
intent(in) :: cube
430 integer :: ix, iy, iz, ixx(3), db(3)
431 integer :: lx, ly, lz, n1, n2, n3
432 real(real64) :: temp(3), modg2, ecut, weight
433 real(real64) :: gpar, gz, r_c, gg(3), default_r_c
434 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
438 db(1:3) = cube%rs_n_global(1:3)
443 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
457 default_r_c = db(3)*cube%spacing(3)/
m_two
460 n1 = max(1, cube%fs_n(1))
461 n2 = max(1, cube%fs_n(2))
462 n3 = max(1, cube%fs_n(3))
464 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
467 temp(1:3) =
m_two*
m_pi/(db(1:3)*cube%spacing(1:3))
472 ix = cube%fs_istart(1) + lx - 1
475 iy = cube%fs_istart(2) + ly - 1
478 iz = cube%fs_istart(3) + lz - 1
483 if(sum(gg(1:2)**2) >
m_two*ecut*1.001_real64) cycle
485 if (abs(modg2) > tol_vanishing_q)
then
487 gpar =
hypot(gg(1), gg(2))
491 fft_coulb_fs(lx, ly, lz) = -
m_half*r_c**2
493 fft_coulb_fs(lx, ly, lz) = weight*fft_coulb_fs(lx, ly, lz)
501 safe_deallocate_a(fft_coulb_fs)
511 class(
space_t),
intent(in) :: space
512 type(
cube_t),
intent(in) :: cube
516 real(real64),
allocatable :: x(:), y(:)
517 integer :: ix, iy, iz, ixx(3), db(3), k, ngp
518 integer :: lx, ly, lz, n1, n2, n3, lxx(3)
519 real(real64) :: temp(3), modg2, xmax, weight
520 real(real64) :: gperp, gx, gy, gz, r_c, gg(3), default_r_c
521 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
528 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
531 db(1:3) = cube%rs_n_global(1:3)
533 default_r_c = maxval(db(2:3)*cube%spacing(2:3)/
m_two)
536 n1 = max(1, cube%fs_n(1))
537 n2 = max(1, cube%fs_n(2))
538 n3 = max(1, cube%fs_n(3))
540 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
543 temp(1:3) =
m_two*
m_pi/(db(1:3)*cube%spacing(1:3))
545 if (.not. space%is_periodic())
then
547 safe_allocate(x(1:ngp))
548 safe_allocate(y(1:ngp))
553 ix = cube%fs_istart(1) + lx - 1
555 lxx(1) = ixx(1) - cube%fs_istart(1) + 1
558 if (.not. space%is_periodic())
then
560 xmax = norm2(temp(2:3)*db(2:3))/2
562 x(k) = (k-1)*(xmax/(ngp-1))
564 maxval(norm2(cube%latt%rlattice_primitive(:, 2:3), dim=1)))
570 iy = cube%fs_istart(2) + ly - 1
572 lxx(2) = ixx(2) - cube%fs_istart(2) + 1
574 iz = cube%fs_istart(3) + lz - 1
576 lxx(3) = ixx(3) - cube%fs_istart(3) + 1
580 if (abs(modg2) > tol_vanishing_q)
then
581 gperp =
hypot(gg(2), gg(3))
582 if (space%periodic_dim == 1)
then
583 if (gperp > r_c)
then
584 fft_coulb_fs(lx, ly, lz) =
m_zero
588 else if (.not. space%is_periodic())
then
592 fft_coulb_fs(lx, ly, lz) =
spline_eval(cylinder_cutoff_f, gperp)
595 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, -lxx(2) + 1, lz)
598 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, ly, -lxx(3) + 1)
601 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, -lxx(2) + 1, -lxx(3) + 1)
606 if (space%periodic_dim == 1)
then
608 else if (.not. space%is_periodic())
then
610 norm2(cube%latt%rlattice_primitive(:, 1)), maxval(norm2(cube%latt%rlattice_primitive(:, 2:3), dim=1)))
614 fft_coulb_fs(lx, ly, lz) = weight*fft_coulb_fs(lx, ly, lz)
618 if (.not. space%is_periodic())
then
625 safe_deallocate_a(fft_coulb_fs)
637 type(
cube_t),
intent(in) :: cube
638 integer,
intent(in) :: kernel
640 logical,
intent(in) :: is_periodic
642 integer :: ix, iy, iz, ixx(3), db(3), lx, ly, lz, n1, n2, n3
643 real(real64) :: temp(3), modg2, ecut, weight
644 real(real64) :: r_c, gg(3), default_r_c
645 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
646 real(real64) :: axis(3,3)
653 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
656 db(1:3) = cube%rs_n_global(1:3)
662 axis(:,ix) = cube%latt%rlattice_primitive(:, ix) * cube%spacing(ix) * db(ix) /
m_two
671 if (.not. cube%latt%nonorthogonal)
then
672 temp(1:3) = axis(:, ix)
673 default_r_c = min(default_r_c, norm2(temp(1:3)))
682 temp = temp / norm2(temp)
683 default_r_c = min(default_r_c, dot_product(temp, axis(:, ix)-axis(:, iy)))
689 n1 = max(1, cube%fs_n(1))
690 n2 = max(1, cube%fs_n(2))
691 n3 = max(1, cube%fs_n(3))
695 safe_allocate(fft_coulb_fs(1:n1,1:n2,1:n3))
698 temp(1:3) =
m_two*
m_pi/(db(1:3)*cube%spacing(1:3))
703 ix = cube%fs_istart(1) + lx - 1
706 iy = cube%fs_istart(2) + ly - 1
709 iz = cube%fs_istart(3) + lz - 1
716 modg2=cube%Lfs(ix,1)**2+cube%Lfs(iy,2)**2+cube%Lfs(iz,3)**2
717 r_c = default_r_c*
m_two
721 if(modg2 >
m_two*ecut*1.001_real64 .and. is_periodic) cycle
723 if (abs(modg2) > tol_vanishing_q)
then
728 fft_coulb_fs(lx, ly, lz) = weight/modg2
733 fft_coulb_fs(lx, ly, lz) = weight*r_c**2/
m_two
735 fft_coulb_fs(lx, ly, lz) =
m_zero
744 safe_deallocate_a(fft_coulb_fs)
754 type(
cube_t),
intent(in) :: cube
758 integer :: i, ix, iy, ixx(2), db(2), npoints
759 real(real64) :: temp(2), vec, r_c, maxf, dk, default_r_c, weight
760 real(real64),
allocatable :: x(:), y(:)
761 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
768 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
770 db(1:2) = cube%rs_n_global(1:2)
772 default_r_c = maxval(db(1:2)*cube%spacing(1:2)/
m_two)
778 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
780 temp(1:2) =
m_two*
m_pi/(db(1:2)*cube%spacing(1:2))
782 maxf = r_c * norm2(temp(1:2)*db(1:2))/2
784 npoints = nint(maxf/dk)
785 safe_allocate(x(1:npoints))
786 safe_allocate(y(1:npoints))
790 x(i) = (i-1) * maxf / (npoints-1)
795 do iy = 1, cube%fs_n_global(2)
797 do ix = 1, cube%fs_n_global(1)
799 vec = norm2(temp(1:2)*ixx(1:2))
801 if (vec*r_c >= x(npoints))
then
802 fft_coulb_fs(ix, iy, 1) = weight * y(npoints)
803 else if (vec >
m_zero)
then
806 fft_coulb_fs(ix, iy, 1) = weight *
m_two *
m_pi * r_c
813 safe_deallocate_a(fft_coulb_fs)
826 type(
cube_t),
intent(in) :: cube
829 integer :: ix, iy, ixx(2), db(2)
830 real(real64) :: temp(2), r_c, gx, gy, default_r_c, weight
831 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
838 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
841 db(1:2) = cube%rs_n_global(1:2)
843 default_r_c = db(2)*cube%spacing(2)/
m_two
847 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
849 temp(1:2) =
m_two*
m_pi/(db(1:2)*cube%spacing(1:2))
853 do iy = 2, cube%fs_n_global(2)
859 do ix = 2, cube%fs_n_global(1)
871 safe_deallocate_a(fft_coulb_fs)
881 type(
cube_t),
intent(in) :: cube
884 integer :: ix, iy, ixx(2), db(2)
885 real(real64) :: temp(2), vec, weight
886 real(real64),
allocatable :: fft_coulb_FS(:,:,:)
893 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
895 db(1:2) = cube%rs_n_global(1:2)
898 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
900 temp(1:2) =
m_two*
m_pi/(db(1:2)*cube%spacing(1:2))
902 do iy = 1, cube%fs_n_global(2)
904 do ix = 1, cube%fs_n_global(1)
906 vec =
sqrt((temp(1) * ixx(1))**2 + (temp(2) * ixx(2))**2)
907 if (vec >
m_zero) fft_coulb_fs(ix, iy, 1) =
m_two *
m_pi / vec * weight
913 safe_deallocate_a(fft_coulb_fs)
921 type(
cube_t),
intent(in) :: cube
923 real(real64),
intent(in) :: poisson_soft_coulomb_param
927 real(real64),
allocatable :: fft_coulb_fs(:, :, :), weight
934 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
936 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
940 do ix = 1, cube%fs_n_global(1)
942 g = (ixx + coulb%qq(1))*
m_two*
m_pi/abs(cube%latt%rlattice(1,1))
943 if (abs(g) > tol_vanishing_q)
then
944 fft_coulb_fs(ix, 1, 1) =
m_two *
loct_bessel_k0(poisson_soft_coulomb_param*abs(g)) * weight
946 fft_coulb_fs(ix, 1, 1) = coulb%singularity *
m_two * weight
951 safe_deallocate_a(fft_coulb_fs)
961 type(
cube_t),
intent(in) :: cube
963 real(real64),
intent(in) :: poisson_soft_coulomb_param
965 integer :: box(1), ixx(1), ix
966 real(real64) :: temp(1), g, r_c, default_r_c, weight
967 real(real64),
allocatable :: fft_coulb_fs(:, :, :)
974 if(coulb%alpha >
m_epsilon) weight = weight * coulb%alpha
976 box(1:1) = cube%rs_n_global(1:1)
978 default_r_c = box(1)*cube%spacing(1)/
m_two
981 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
983 temp(1:1) =
m_two*
m_pi/(box(1:1)*cube%spacing(1:1))
986 do ix = 1, cube%fs_n_global(1)
993 safe_deallocate_a(fft_coulb_fs)
1013#include "poisson_fft_inc.F90"
1015#include "complex.F90"
1016#include "poisson_fft_inc.F90"
Some operations may be done for one spline-function, or for an array of them.
double hypot(double __x, double __y) __attribute__((__nothrow__
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
real(real64) function, public fft_get_ecut_from_box(box_dim, fs_istart, latt, gspacing, periodic_dim, qq)
Given an fft box (fixed by the real-space grid), it returns the cutoff energy of the sphere that fits...
subroutine, public fft_gg_transform(gg_in, temp, periodic_dim, latt, qq, gg, modg2)
pure integer function, public pad_feq(ii, nn, mode)
convert between array index and G-vector
integer, parameter, public fftlib_nfft
subroutine, public fourier_space_op_end(this)
subroutine, public dfourier_space_op_init(this, cube, op, in_device)
real(real64), parameter, public m_two
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public m_pi
some mathematical constants
real(real64), parameter, public m_fourth
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_half
real(real64), parameter, public m_one
This module is intended to contain "only mathematical" functions and procedures.
pure real(real64) function, dimension(1:3), public dcross_product(a, b)
This module defines the meshes, which are used in Octopus.
subroutine, public messages_warning(no_lines, all_nodes, namespace)
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
real(real64) function, public poisson_cutoff_3d_2d(p, z, r)
real(real64) function, public poisson_cutoff_3d_1d(x, p, rmax)
real(real64) function, public poisson_cutoff_3d_0d(x, r)
integer, parameter, public poisson_fft_kernel_hockney
subroutine poisson_fft_build_2d_0d(namespace, cube, coulb)
A. Castro et al., Phys. Rev. B 80, 033102 (2009)
subroutine poisson_fft_build_3d_1d(namespace, space, cube, coulb)
C. A. Rozzi et al., Phys. Rev. B 73, 205119 (2006), Table I.
subroutine poisson_fft_build_3d_2d(namespace, cube, coulb)
C. A. Rozzi et al., Phys. Rev. B 73, 205119 (2006), Table I.
integer, parameter, public poisson_fft_kernel_nocut
integer, parameter, public poisson_fft_kernel_cyl
subroutine poisson_fft_build_2d_1d(namespace, cube, coulb)
A. Castro et al., Phys. Rev. B 80, 033102 (2009)
subroutine poisson_fft_build_1d_0d(namespace, cube, coulb, poisson_soft_coulomb_param)
subroutine, public zpoisson_fft_solve(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm)
subroutine poisson_fft_build_3d_0d(namespace, cube, kernel, coulb, is_periodic)
C. A. Rozzi et al., Phys. Rev. B 73, 205119 (2006), Table I.
subroutine get_cutoff(namespace, default_r_c, r_c)
subroutine poisson_fft_build_3d_3d(cube, coulb)
subroutine poisson_fft_build_1d_1d(cube, coulb, poisson_soft_coulomb_param)
subroutine, public poisson_fft_get_kernel(namespace, space, cube, coulb, kernel, soft_coulb_param, fullcube)
subroutine, public poisson_fft_end(this)
subroutine poisson_fft_build_2d_2d(cube, coulb)
A. Castro et al., Phys. Rev. B 80, 033102 (2009)
subroutine, public poisson_fft_init(this, namespace, space, cube, kernel, soft_coulb_param, fullcube)
integer, parameter, public poisson_fft_kernel_pla
integer, parameter, public poisson_fft_kernel_corrected
integer, parameter, public poisson_fft_kernel_sph
subroutine, public dpoisson_fft_solve(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm)
subroutine poisson_fft_build_3d_3d_hockney(cube, coulb, fullcube)
Kernel for Hockneys algorithm that solves the poisson equation in a small box while respecting the pe...
subroutine, public spline_fit(nrc, rofi, ffit, spl, threshold)
real(real64) function, public spline_eval(spl, x)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
type(unit_system_t), public units_inp
the units systems for reading and writing
the basic spline datatype