Octopus
poisson_fft.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2011 M. Marques, A. Castro, A. Rubio, G. Bertsch, M. Oliveira
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
22 use accel_oct_m
24 use cube_oct_m
25 use debug_oct_m
26 use fft_oct_m
28 use global_oct_m
29 use, intrinsic :: iso_fortran_env
32 use math_oct_m
34 use mesh_oct_m
37 use parser_oct_m
40 use space_oct_m
43 use unit_oct_m
45 use xc_cam_oct_m, only: cam_null
46
47 implicit none
48 private
49 public :: &
62
63 integer, public, parameter :: &
64 POISSON_FFT_KERNEL_NONE = -1, &
71
72 type poisson_fft_t
73 ! Components are public by default
74 type(fourier_space_op_t) :: coulb
75 integer :: kernel
76 real(real64) :: soft_coulb_param
77 end type poisson_fft_t
78
79 real(real64), parameter :: TOL_VANISHING_Q = 1e-6_real64
80contains
81
82 subroutine poisson_fft_init(this, namespace, space, cube, kernel, soft_coulb_param, fullcube)
83 type(poisson_fft_t), intent(out) :: this
84 type(namespace_t), intent(in) :: namespace
85 class(space_t), intent(in) :: space
86 type(cube_t), intent(inout) :: cube
87 integer, intent(in) :: kernel
88 real(real64), optional, intent(in) :: soft_coulb_param
89 type(cube_t), optional, intent(in) :: fullcube
90
91 real(real64) :: qvector(1:space%dim)
92
93 push_sub(poisson_fft_init)
94
95 this%kernel = kernel
96 this%soft_coulb_param = optional_default(soft_coulb_param, m_zero)
97 qvector = m_zero
98 call this%coulb%init(space, qvector, cam_null)
99
100 call poisson_fft_get_kernel(namespace, space, cube, this%coulb, kernel, soft_coulb_param, fullcube)
101
102 pop_sub(poisson_fft_init)
103 end subroutine poisson_fft_init
104
105 subroutine poisson_fft_get_kernel(namespace, space, cube, coulb, kernel, soft_coulb_param, fullcube)
106 type(namespace_t), intent(in) :: namespace
107 class(space_t), intent(in) :: space
108 type(cube_t), intent(in) :: cube
109 type(fourier_space_op_t), intent(inout) :: coulb
110 integer, intent(in) :: kernel
111 real(real64), optional, intent(in) :: soft_coulb_param
112 type(cube_t), optional, intent(in) :: fullcube
113
114 push_sub(poisson_fft_get_kernel)
115
116 if (coulb%mu > m_epsilon) then
117 if (space%dim /= 3 .or. kernel /= poisson_fft_kernel_nocut) then
118 message(1) = "The screened Coulomb potential is only implemented in 3D for PoissonFFTKernel=fft_nocut."
119 call messages_fatal(1, namespace=namespace)
120 end if
121 end if
122
123
124 if (kernel == poisson_fft_kernel_hockney) then
125 if (.not. present(fullcube)) then
126 message(1) = "Hockney's FFT-kernel needs cube of full unit cell "
127 call messages_fatal(1, namespace=namespace)
128 else
129 if (.not. allocated(fullcube%fft)) then
130 message(1) = "Hockney's FFT-kernel needs PoissonSolver=fft"
131 call messages_fatal(1, namespace=namespace)
132 end if
133 end if
134 end if
135
136
137 select case (space%dim)
138 case (1)
139 assert(present(soft_coulb_param))
140 select case (kernel)
142 call poisson_fft_build_1d_0d(namespace, cube, coulb, soft_coulb_param)
144 call poisson_fft_build_1d_1d(cube, coulb, soft_coulb_param)
145 case default
146 message(1) = "Invalid Poisson FFT kernel for 1D."
147 call messages_fatal(1, namespace=namespace)
148 end select
149
150 case (2)
151 select case (kernel)
153 call poisson_fft_build_2d_0d(namespace, cube, coulb)
155 call poisson_fft_build_2d_1d(namespace, cube, coulb)
157 call poisson_fft_build_2d_2d(cube, coulb)
158 case default
159 message(1) = "Invalid Poisson FFT kernel for 2D."
160 call messages_fatal(1, namespace=namespace)
161 end select
162
163 case (3)
164 select case (kernel)
166 call poisson_fft_build_3d_0d(namespace, cube, kernel, coulb, space%is_periodic())
169 call poisson_fft_build_3d_1d(namespace, space, cube, coulb)
172 call poisson_fft_build_3d_2d(namespace, cube, coulb)
173
175 call poisson_fft_build_3d_3d(cube, coulb)
176
178 call poisson_fft_build_3d_3d_hockney(cube, coulb, fullcube)
179
180 case default
181 message(1) = "Invalid Poisson FFT kernel for 3D."
182 call messages_fatal(1, namespace=namespace)
183 end select
184 end select
185
187 end subroutine poisson_fft_get_kernel
188
189 !-----------------------------------------------------------------
190
191 subroutine get_cutoff(namespace, default_r_c, r_c)
192 type(namespace_t), intent(in) :: namespace
193 real(real64), intent(in) :: default_r_c
194 real(real64), intent(out) :: r_c
195
196 push_sub(get_cutoff)
197
198 call parse_variable(namespace, 'PoissonCutoffRadius', default_r_c, r_c, units_inp%length)
199
200 call messages_write('Info: Poisson Cutoff Radius =')
201 call messages_write(r_c, units = units_out%length, fmt = '(f6.1)')
202 call messages_info()
203
204 if (r_c > default_r_c + m_epsilon) then
205 call messages_write('Poisson cutoff radius is larger than cell size.', new_line = .true.)
206 call messages_write('You can see electrons in neighboring cell(s).')
207 call messages_warning()
208 end if
209
210 pop_sub(get_cutoff)
211 end subroutine get_cutoff
212
213
215 function poisson_fft_singularity_3d(coulb) result(singularity_term)
216 type(fourier_space_op_t), intent(in) :: coulb
217
218 real(real64) :: singularity_term
219
220 real(real64) :: inv_four_mu2
221
223
224 if (coulb%mu > m_epsilon) then
225 inv_four_mu2 = m_one/((m_two*coulb%mu)**2)
226 else
227 inv_four_mu2 = m_zero
228 end if
229
230 ! Screened short-range coulomb potential (erfc function)
231 if (coulb%mu > m_epsilon .and. abs(coulb%alpha) < m_epsilon) then
232 ! Analytical limit of 4pi/q^2 * (1-beta*exp(-|q|^2/4mu^2))
233 singularity_term = m_four * m_pi * inv_four_mu2 * coulb%beta
234 else ! We use the user-defined value of the singularity
235 ! Long-range screened singularity
236 if (abs(coulb%alpha) > m_epsilon) then
237 singularity_term = coulb%singularity*coulb%alpha + m_four * m_pi * inv_four_mu2 * coulb%beta
238 else
239 singularity_term = coulb%singularity
240 end if
241 ! 4pi/q^2 * alpha
242 end if
243
245
246 end function poisson_fft_singularity_3d
247
272 subroutine poisson_fft_build_3d_3d(cube, coulb)
273 type(cube_t), intent(in) :: cube
274 type(fourier_space_op_t), intent(inout) :: coulb
275
276 integer :: n1, n2, n3, lx, ly, lz, i
277 real(real64) :: modg2, modgyz, beta, modg2_cutoff, inv_four_mu2, ecut
278 real(real64) :: temp(3), diag_temp(3, 3), metric(3, 3), a(3, 3)
279 real(real64) :: q1, q2, q3, ux, uy, uz, a11, two_a12, two_a13, a22, two_a23, a33, four_a11
280 real(real64) :: singularity_term
281 real(real64), allocatable :: fft_coulb_fs(:,:,:)
282
284
285 if (coulb%mu > m_epsilon) then
286 inv_four_mu2 = m_one/((m_two*coulb%mu)**2)
287 else
288 inv_four_mu2 = m_zero
289 end if
290
291 n1 = max(1, cube%fs_n(1))
292 n2 = max(1, cube%fs_n(2))
293 n3 = max(1, cube%fs_n(3))
294
295 ! Define q+G = 0 term
296 singularity_term = poisson_fft_singularity_3d(coulb)
297
298 ! store the Fourier transform of the Coulomb interaction
299 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
300
301 ! G vector cutoff
302 temp = m_two * m_pi / cube%length()
303 ecut = fft_get_ecut_from_box(cube%rs_n_global, cube%fs_istart, cube%latt, temp, 3, coulb%qq)
304
305 ! metric = B^T B
306 metric = matmul(transpose(cube%latt%klattice_primitive), cube%latt%klattice_primitive)
307
308 ! A = D (B^T B) D
309 diag_temp = m_zero
310 do i = 1, 3
311 diag_temp(i, i) = temp(i)
312 enddo
313 a = matmul(diag_temp, matmul(metric, diag_temp))
314 a11 = a(1, 1)
315 a22 = a(2, 2)
316 a33 = a(3, 3)
317 two_a12 = m_two * a(1, 2)
318 two_a13 = m_two * a(1, 3)
319 two_a23 = m_two * a(2, 3)
320 four_a11 = m_four * a11
321
322 q1 = coulb%qq(1)
323 q2 = coulb%qq(2)
324 q3 = coulb%qq(3)
325
326 modg2_cutoff = m_two * ecut * 1.001_real64
327
328 do lz = 1, n3
329 ! u=G+q (integer-mode coords)
330 uz = real(cube%fs_ifz(lz), real64) + q3
331
332 do ly = 1, n2
333 uy = real(cube%fs_ify(ly), real64) + q2
334 modgyz = a22*uy*uy + two_a23*uy*uz + a33*uz*uz
335 beta = two_a12*uy + two_a13*uz
336 if (modgyz - beta * beta / four_a11 > modg2_cutoff) then
337 fft_coulb_fs(1:n1, ly, lz) = m_zero
338 cycle
339 end if
340
341 do lx = 1, n1
342 ux = real(cube%fs_ifx(lx), real64) + q1
343 ! Cartesian |G + q|^2
344 modg2 = (a11*ux + beta)*ux + modgyz
345
346 if (modg2 > modg2_cutoff) then
347 fft_coulb_fs(lx, ly, lz) = m_zero
348 else if (modg2 > tol_vanishing_q) then
349 !Screened coulomb potential (erfc function)
350 if (coulb%mu > m_epsilon) then
351 if(abs(coulb%alpha) > m_epsilon) then ! CAM
352 fft_coulb_fs(lx, ly, lz) = m_four * m_pi / modg2 * (coulb%alpha - coulb%beta * expm1(-modg2*inv_four_mu2))
353 else ! purely short-range screened
354 fft_coulb_fs(lx, ly, lz) = m_four * m_pi / modg2 * coulb%beta * (-expm1(-modg2 * inv_four_mu2))
355 end if
356 else
357 if (abs(coulb%alpha) > m_epsilon) then ! global screened hybrids
358 fft_coulb_fs(lx, ly, lz) = m_four * m_pi / modg2 * coulb%alpha
359 else ! Bare interaction
360 fft_coulb_fs(lx, ly, lz) = m_four * m_pi / modg2
361 end if
362 end if
363 else ! This is the term q+G = 0
364 fft_coulb_fs(lx, ly, lz) = singularity_term
365 end if
366
367 end do
368 end do
369 end do
370
371 call coulb%dset_op(cube, op_move = fft_coulb_fs)
372
373 safe_deallocate_a(fft_coulb_fs)
374
376
377 end subroutine poisson_fft_build_3d_3d
378
379
384 subroutine poisson_fft_build_3d_3d_hockney(cube, coulb, fullcube)
385 type(cube_t), intent(in) :: cube
386 type(fourier_space_op_t), intent(inout) :: coulb
387 type(cube_t), intent(in) :: fullcube
388
389 integer :: ix, iy, iz, ixx(3), db(3), nfs(3), nrs(3), nfs_s(3), nrs_s(3), dnrs(3)
390 real(real64) :: temp(3), modg2, weight
391 real(real64) :: gg(3)
392 real(real64), allocatable :: fft_Coulb_small_RS(:,:,:,:)
393 real(real64), allocatable :: fft_Coulb_RS(:,:,:,:)
394 complex(real64), allocatable :: fft_Coulb_small_FS(:,:,:,:)
395 complex(real64), allocatable :: fft_Coulb_FS(:,:,:,:)
396 integer, parameter :: howmany = 1
397
399
400 assert(abs(coulb%mu) < m_epsilon)
401 assert(cube%batch_capacity == 1)
402 assert(fullcube%batch_capacity == 1)
403
404 ! dimensions of large boxes
405 nfs(1:3) = fullcube%fs_n_global(1:3)
406 nrs(1:3) = fullcube%rs_n_global(1:3)
407
408 safe_allocate(fft_coulb_fs(1:nfs(1),1:nfs(2),1:nfs(3), 1:howmany))
409 safe_allocate(fft_coulb_rs(1:nrs(1),1:nrs(2),1:nrs(3), 1:howmany))
410
411 ! dimensions of small boxes x_s
412 nfs_s(1:3) = cube%fs_n_global(1:3)
413 nrs_s(1:3) = cube%rs_n_global(1:3)
414
415 safe_allocate(fft_coulb_small_fs(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3), 1:howmany))
416 safe_allocate(fft_coulb_small_rs(1:nrs_s(1),1:nrs_s(2),1:nrs_s(3), 1:howmany))
417
418 ! build full periodic Coulomb potenital in Fourier space
419 fft_coulb_fs = m_zero
420
421 db(1:3) = fullcube%rs_n_global(1:3)
422 temp(1:3) = m_two*m_pi/(db(1:3)*cube%spacing(1:3))
423
424 do iz = 1, nfs(3)
425 ixx(3) = pad_feq(iz, db(3), .true.)
426 do iy = 1, nfs(2)
427 ixx(2) = pad_feq(iy, db(2), .true.)
428 do ix = 1, nfs(1)
429 ixx(1) = pad_feq(ix, db(1), .true.)
430
431 call fft_gg_transform(ixx, temp, 3, cube%latt, coulb%qq, gg, modg2)
432
433 if (abs(modg2) > tol_vanishing_q) then
434 fft_coulb_fs(ix, iy, iz, 1) = m_one/modg2
435 else
436 fft_coulb_fs(ix, iy, iz, 1) = m_zero
437 end if
438 end do
439 end do
440 end do
441
442 ! Full range hybrids weight
443 weight = m_four*m_pi
444 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
445
446 do iz = 1, nfs(3)
447 do iy = 1, nfs(2)
448 do ix = 1, nfs(1)
449 fft_coulb_fs(ix, iy, iz, 1) = weight*fft_coulb_fs(ix, iy, iz, 1)
450 end do
451 end do
452 end do
453
454 ! get periodic Coulomb potential in real space
455 call dfft_backward(fullcube%fft, fft_coulb_fs, fft_coulb_rs)
456
457 ! copy to small box by respecting this pattern
458 ! full periodic coulomb: |abc--------------------------xyz|
459 ! Hockney: |abcxyz|
460 dnrs = nrs - nrs_s
461
462 do iz = 1, nrs_s(3)
463 ixx(3) = iz
464 if (iz > nrs_s(3)/2+1) ixx(3) = ixx(3) + dnrs(3)
465 do iy = 1, nrs_s(2)
466 ixx(2) = iy
467 if (iy > nrs_s(2)/2+1) ixx(2) = ixx(2) + dnrs(2)
468 do ix = 1, nrs_s(1)
469 ixx(1) = ix
470 if (ix > nrs_s(1)/2+1) ixx(1) = ixx(1) + dnrs(1)
471 fft_coulb_small_rs(ix, iy, iz, 1) = fft_coulb_rs(ixx(1),ixx(2),ixx(3), 1)
472 end do
473 end do
474 end do
475 ! make Hockney kernel in Fourier space
476 call dfft_forward(cube%fft, fft_coulb_small_rs, fft_coulb_small_fs)
477 !dummy copy for type conversion
478 fft_coulb_small_rs(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3),1:howmany) = &
479 real( fft_Coulb_small_FS(1:nfs_s(1),1:nfs_s(2),1:nfs_s(3),1:howmany), real64)
480
481
482 ! Restrict array to local part to support pfft
483 ! For FFTW this reduces simply to the full array
484 call coulb%dset_op(cube, &
485 fft_coulb_small_rs(cube%fs_istart(1):cube%fs_istart(1)+cube%fs_n(1), &
486 cube%fs_istart(2):cube%fs_istart(2)+cube%fs_n(2), &
487 cube%fs_istart(3):cube%fs_istart(3)+cube%fs_n(3), 1))
488
489 safe_deallocate_a(fft_coulb_fs)
490 safe_deallocate_a(fft_coulb_rs)
491 safe_deallocate_a(fft_coulb_small_fs)
492 safe_deallocate_a(fft_coulb_small_rs)
493
495
497
498 !-----------------------------------------------------------------
500 subroutine poisson_fft_build_3d_2d(namespace, cube, coulb)
501 type(namespace_t), intent(in) :: namespace
502 type(cube_t), intent(in) :: cube
503 type(fourier_space_op_t), intent(inout) :: coulb
504
505 integer :: ix, iy, iz, ixx(3), db(3)
506 integer :: lx, ly, lz, n1, n2, n3
507 real(real64) :: temp(3), modg2, ecut, weight
508 real(real64) :: gpar, gz, r_c, gg(3), default_r_c
509 real(real64), allocatable :: fft_coulb_FS(:,:,:)
510
512
513 db(1:3) = cube%rs_n_global(1:3)
514
515 assert(abs(coulb%mu) < m_epsilon)
516 ! Full range hybrids weight
517 weight = m_four*m_pi
518 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
519
520
521 !%Variable PoissonCutoffRadius
522 !%Type float
523 !%Section Hamiltonian::Poisson
524 !%Description
525 !% When <tt>PoissonSolver = fft</tt> and <tt>PoissonFFTKernel</tt> is neither <tt>multipole_corrections</tt>
526 !% nor <tt>fft_nocut</tt>,
527 !% this variable controls the distance after which the electron-electron interaction goes to zero.
528 !% A warning will be written if the value is too large and will cause spurious interactions between images.
529 !% The default is half of the FFT box max dimension in a finite direction.
530 !%End
531
532 default_r_c = db(3)*cube%spacing(3)/m_two
533 call get_cutoff(namespace, default_r_c, r_c)
534
535 n1 = max(1, cube%fs_n(1))
536 n2 = max(1, cube%fs_n(2))
537 n3 = max(1, cube%fs_n(3))
538 ! store the Fourier transform of the Coulomb interaction
539 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
540 fft_coulb_fs = m_zero
541
542 temp(1:3) = m_two*m_pi/(db(1:3)*cube%spacing(1:3))
543
544 ecut = fft_get_ecut_from_box(cube%rs_n_global, cube%fs_istart, cube%latt, temp, 2, coulb%qq)
545
546 do lz = 1, n3
547 iz = cube%fs_istart(3) + lz - 1
548 ixx(3) = pad_feq(iz, db(3), .true.)
549 do ly = 1, n2
550 iy = cube%fs_istart(2) + ly - 1
551 ixx(2) = pad_feq(iy, db(2), .true.)
552 do lx = 1, n1
553 ix = cube%fs_istart(1) + lx - 1
554 ixx(1) = pad_feq(ix, db(1), .true.)
555
556 call fft_gg_transform(ixx, temp, 2, cube%latt, coulb%qq, gg, modg2)
557
558 if(sum(gg(1:2)**2) > m_two*ecut*1.001_real64) cycle
559
560 if (abs(modg2) > tol_vanishing_q) then
561 gz = abs(gg(3))
562 gpar = hypot(gg(1), gg(2))
563 ! note: if gpar = 0, then modg2 = gz**2
564 fft_coulb_fs(lx, ly, lz) = poisson_cutoff_3d_2d(gpar,gz,r_c)/modg2
565 else
566 fft_coulb_fs(lx, ly, lz) = -m_half*r_c**2
567 end if
568 fft_coulb_fs(lx, ly, lz) = weight*fft_coulb_fs(lx, ly, lz)
569 end do
570 end do
571
572 end do
573
574 call coulb%dset_op(cube, op_move = fft_coulb_fs)
575
576 safe_deallocate_a(fft_coulb_fs)
578 end subroutine poisson_fft_build_3d_2d
579 !-----------------------------------------------------------------
580
581
582 !-----------------------------------------------------------------
584 subroutine poisson_fft_build_3d_1d(namespace, space, cube, coulb)
585 type(namespace_t), intent(in) :: namespace
586 class(space_t), intent(in) :: space
587 type(cube_t), intent(in) :: cube
588 type(fourier_space_op_t), intent(inout) :: coulb
589
590 type(spline_t) :: cylinder_cutoff_f
591 real(real64), allocatable :: x(:), y(:)
592 integer :: ix, iy, iz, ixx(3), db(3), k, ngp
593 integer :: lx, ly, lz, n1, n2, n3, lxx(3)
594 real(real64) :: temp(3), modg2, xmax, weight
595 real(real64) :: gperp, gx, gy, gz, r_c, gg(3), default_r_c
596 real(real64), allocatable :: fft_coulb_FS(:,:,:)
597
599
600 assert(abs(coulb%mu) < m_epsilon)
601 ! Full range hybrids weight
602 weight = m_four*m_pi
603 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
604
605
606 db(1:3) = cube%rs_n_global(1:3)
607
608 default_r_c = maxval(db(2:3)*cube%spacing(2:3)/m_two)
609 call get_cutoff(namespace, default_r_c, r_c)
610
611 n1 = max(1, cube%fs_n(1))
612 n2 = max(1, cube%fs_n(2))
613 n3 = max(1, cube%fs_n(3))
614 ! store the Fourier transform of the Coulomb interaction
615 safe_allocate(fft_coulb_fs(1:n1, 1:n2, 1:n3))
616 fft_coulb_fs = m_zero
617
618 temp(1:3) = m_two*m_pi/(db(1:3)*cube%spacing(1:3))
619
620 if (.not. space%is_periodic()) then
621 ngp = 8*db(2)
622 safe_allocate(x(1:ngp))
623 safe_allocate(y(1:ngp))
624 end if
625
626 ! Note(Alex) This loop ordering results in bad memory access for fft_Coulb_FS
627 ! It should be refactored
628 do lx = 1, n1
629 ix = cube%fs_istart(1) + lx - 1
630 ixx(1) = pad_feq(ix, db(1), .true.)
631 lxx(1) = ixx(1) - cube%fs_istart(1) + 1
632 gx = temp(1)*ixx(1)
633
634 if (.not. space%is_periodic()) then
635 call spline_init(cylinder_cutoff_f)
636 xmax = norm2(temp(2:3)*db(2:3))/2
637 do k = 1, ngp
638 x(k) = (k-1)*(xmax/(ngp-1))
639 y(k) = poisson_cutoff_3d_1d_finite(gx, x(k), norm2(cube%latt%rlattice_primitive(:, 1)), &
640 maxval(norm2(cube%latt%rlattice_primitive(:, 2:3), dim=1)))
641 end do
642 call spline_fit(ngp, x, y, cylinder_cutoff_f, m_zero)
643 end if
644
645 do ly = 1, n2
646 iy = cube%fs_istart(2) + ly - 1
647 ixx(2) = pad_feq(iy, db(2), .true.)
648 lxx(2) = ixx(2) - cube%fs_istart(2) + 1
649 do lz = 1, n3
650 iz = cube%fs_istart(3) + lz - 1
651 ixx(3) = pad_feq(iz, db(3), .true.)
652 lxx(3) = ixx(3) - cube%fs_istart(3) + 1
653
654 call fft_gg_transform(ixx, temp, 1, cube%latt, coulb%qq, gg, modg2)
655
656 if (abs(modg2) > tol_vanishing_q) then
657 gperp = hypot(gg(2), gg(3))
658 if (space%periodic_dim == 1) then
659 if (gperp > r_c) then
660 fft_coulb_fs(lx, ly, lz) = m_zero
661 else
662 fft_coulb_fs(lx, ly, lz) = poisson_cutoff_3d_1d(abs(gx), gperp, r_c)/modg2
663 end if
664 else if (.not. space%is_periodic()) then
665 gy = gg(2)
666 gz = gg(3)
667 if ((gz >= m_zero) .and. (gy >= m_zero)) then
668 fft_coulb_fs(lx, ly, lz) = spline_eval(cylinder_cutoff_f, gperp)
669 end if
670 if ((gz >= m_zero) .and. (gy < m_zero)) then
671 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, -lxx(2) + 1, lz)
672 end if
673 if ((gz < m_zero) .and. (gy >= m_zero)) then
674 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, ly, -lxx(3) + 1)
675 end if
676 if ((gz < m_zero) .and. (gy < m_zero)) then
677 fft_coulb_fs(lx, ly, lz) = fft_coulb_fs(lx, -lxx(2) + 1, -lxx(3) + 1)
678 end if
679 end if
680
681 else
682 if (space%periodic_dim == 1) then
683 fft_coulb_fs(lx, ly, lz) = -(m_half*log(r_c) - m_fourth)*r_c**2
684 else if (.not. space%is_periodic()) then
685 fft_coulb_fs(lx, ly, lz) = poisson_cutoff_3d_1d_finite(m_zero, m_zero, &
686 norm2(cube%latt%rlattice_primitive(:, 1)), maxval(norm2(cube%latt%rlattice_primitive(:, 2:3), dim=1)))
687 end if
688
689 end if
690 fft_coulb_fs(lx, ly, lz) = weight*fft_coulb_fs(lx, ly, lz)
691 end do
692 end do
693
694 if (.not. space%is_periodic()) then
695 call spline_end(cylinder_cutoff_f)
696 end if
697 end do
698
699 call coulb%dset_op(cube, op_move = fft_coulb_fs)
700
701 safe_deallocate_a(fft_coulb_fs)
702 safe_deallocate_a(x)
703 safe_deallocate_a(y)
705 end subroutine poisson_fft_build_3d_1d
706 !-----------------------------------------------------------------
707
708
709 !-----------------------------------------------------------------
711 subroutine poisson_fft_build_3d_0d(namespace, cube, kernel, coulb, is_periodic)
712 type(namespace_t), intent(in) :: namespace
713 type(cube_t), intent(in) :: cube
714 integer, intent(in) :: kernel
715 type(fourier_space_op_t), intent(inout) :: coulb
716 logical, intent(in) :: is_periodic
717
718 integer :: ix, iy, iz, ixx(3), db(3), lx, ly, lz, n1, n2, n3
719 real(real64) :: temp(3), modg2, ecut, weight
720 real(real64) :: r_c, gg(3), default_r_c
721 real(real64), allocatable :: fft_coulb_FS(:,:,:)
722 real(real64) :: axis(3,3)
723
725
726 assert(abs(coulb%mu) < m_epsilon)
727 ! Full range hybrids weight
728 weight = m_four*m_pi
729 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
730
731
732 db(1:3) = cube%rs_n_global(1:3)
733
734 if (kernel /= poisson_fft_kernel_corrected) then
735
736 ! This is the real-space cutoff
737 do ix = 1, 3
738 axis(:,ix) = cube%latt%rlattice_primitive(:, ix) * cube%spacing(ix) * db(ix) / m_two
739 end do
740
741 default_r_c = m_huge
742 do ix = 1, 3
743 iy = mod(ix, 3)+1
744 iz = mod(ix+1, 3)+1
745
746 ! For orthogonal cells, this is determined by the size of the cube
747 if (.not. cube%latt%nonorthogonal) then
748 temp(1:3) = axis(:, ix)
749 default_r_c = min(default_r_c, norm2(temp(1:3)))
750 else
751 ! At the moment, this codepath is only called for DFT+U submesh Poisson solver
752 !
753 ! For non-orthogonal cells, the relevant length is the distance between two planes of
754 ! the parallelepiped. This ensures that we draw a sphere that touches the borders of the box,
755 ! thus avoiding contribution from periodic replicas
756 ! This distance is given by the usual formula of the distance from a point to a plan
757 temp = dcross_product(axis(:, iy), axis(:, iz))
758 temp = temp / norm2(temp)
759 default_r_c = min(default_r_c, dot_product(temp, axis(:, ix)-axis(:, iy)))
760 end if
761 end do
762 call get_cutoff(namespace, default_r_c, r_c)
763 end if
764
765 n1 = max(1, cube%fs_n(1))
766 n2 = max(1, cube%fs_n(2))
767 n3 = max(1, cube%fs_n(3))
768
769 ! store the fourier transform of the Coulomb interaction
770 ! store only the relevant part if PFFT is used
771 safe_allocate(fft_coulb_fs(1:n1,1:n2,1:n3))
772 fft_coulb_fs = m_zero
773
774 temp(1:3) = m_two*m_pi/(db(1:3)*cube%spacing(1:3))
775
776 ecut = fft_get_ecut_from_box(cube%rs_n_global, cube%fs_istart, cube%latt, temp, 3, coulb%qq)
777
778 do lz = 1, n3
779 iz = cube%fs_istart(3) + lz - 1
780 ixx(3) = pad_feq(iz, db(3), .true.)
781 do ly = 1, n2
782 iy = cube%fs_istart(2) + ly - 1
783 ixx(2) = pad_feq(iy, db(2), .true.)
784 do lx = 1, n1
785 ix = cube%fs_istart(1) + lx - 1
786 ixx(1) = pad_feq(ix, db(1), .true.)
787
788 call fft_gg_transform(ixx, temp, 0, cube%latt, coulb%qq, gg, modg2)
789
790 ! At the moment this is only done for periodic space, so for DFT+U Coulomb integrals
791 if(modg2 > m_two*ecut*1.001_real64 .and. is_periodic) cycle
792
793 if (abs(modg2) > tol_vanishing_q) then
794 select case (kernel)
796 fft_coulb_fs(lx, ly, lz) = weight*poisson_cutoff_3d_0d(sqrt(modg2),r_c)/modg2
798 fft_coulb_fs(lx, ly, lz) = weight/modg2
799 end select
800 else
801 select case (kernel)
803 fft_coulb_fs(lx, ly, lz) = weight*r_c**2/m_two
805 fft_coulb_fs(lx, ly, lz) = m_zero
806 end select
807 end if
808 end do
809 end do
810 end do
811
812 call coulb%dset_op(cube, fft_coulb_fs, in_device = (kernel /= poisson_fft_kernel_corrected))
813
814 safe_deallocate_a(fft_coulb_fs)
816 end subroutine poisson_fft_build_3d_0d
817 !-----------------------------------------------------------------
818
819
820 !-----------------------------------------------------------------
822 subroutine poisson_fft_build_2d_0d(namespace, cube, coulb)
823 type(namespace_t), intent(in) :: namespace
824 type(cube_t), intent(in) :: cube
825 type(fourier_space_op_t), intent(inout) :: coulb
826
827 type(spline_t) :: besselintf
828 integer :: i, ix, iy, ixx(2), db(2), npoints
829 real(real64) :: temp(2), vec, r_c, maxf, dk, default_r_c, weight
830 real(real64), allocatable :: x(:), y(:)
831 real(real64), allocatable :: fft_coulb_FS(:,:,:)
832
834
835 assert(abs(coulb%mu) < m_epsilon)
836 ! Full range hybrids weight
837 weight = m_one
838 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
839
840 db(1:2) = cube%rs_n_global(1:2)
841
842 default_r_c = maxval(db(1:2)*cube%spacing(1:2)/m_two)
843 call get_cutoff(namespace, default_r_c, r_c)
844
845 call spline_init(besselintf)
846
847 ! store the fourier transform of the Coulomb interaction
848 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
849 fft_coulb_fs = m_zero
850 temp(1:2) = m_two*m_pi/(db(1:2)*cube%spacing(1:2))
851
852 maxf = r_c * norm2(temp(1:2)*db(1:2))/2
853 dk = 0.25_real64 ! This seems to be reasonable.
854 npoints = nint(maxf/dk)
855 safe_allocate(x(1:npoints))
856 safe_allocate(y(1:npoints))
857 x(1) = m_zero
858 y(1) = m_zero
859 do i = 2, npoints
860 x(i) = (i-1) * maxf / (npoints-1)
861 y(i) = y(i-1) + poisson_cutoff_2d_0d(x(i-1), x(i))
862 end do
863 call spline_fit(npoints, x, y, besselintf, m_zero)
864
865 do iy = 1, cube%fs_n_global(2)
866 ixx(2) = pad_feq(iy, db(2), .true.)
867 do ix = 1, cube%fs_n_global(1)
868 ixx(1) = pad_feq(ix, db(1), .true.)
869 vec = norm2(temp(1:2)*ixx(1:2))
870 ! extra check to avoid extrapolation which leads to an error in gsl
871 if (vec*r_c >= x(npoints)) then
872 fft_coulb_fs(ix, iy, 1) = weight * y(npoints)
873 else if (vec > m_zero) then
874 fft_coulb_fs(ix, iy, 1) = weight * (m_two * m_pi / vec) * spline_eval(besselintf, vec*r_c)
875 else
876 fft_coulb_fs(ix, iy, 1) = weight * m_two * m_pi * r_c
877 end if
878 end do
879 end do
880
881 call coulb%dset_op(cube, op_move = fft_coulb_fs)
882
883 safe_deallocate_a(fft_coulb_fs)
884 safe_deallocate_a(x)
885 safe_deallocate_a(y)
886 call spline_end(besselintf)
888 end subroutine poisson_fft_build_2d_0d
889 !-----------------------------------------------------------------
890
891
892 !-----------------------------------------------------------------
894 subroutine poisson_fft_build_2d_1d(namespace, cube, coulb)
895 type(namespace_t), intent(in) :: namespace
896 type(cube_t), intent(in) :: cube
897 type(fourier_space_op_t), intent(inout) :: coulb
898
899 integer :: ix, iy, ixx(2), db(2)
900 real(real64) :: temp(2), r_c, gx, gy, default_r_c, weight
901 real(real64), allocatable :: fft_coulb_FS(:,:,:)
902
904
905 assert(abs(coulb%mu) < m_epsilon)
906 ! Full range hybrids weight
907 weight = m_one
908 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
909
910
911 db(1:2) = cube%rs_n_global(1:2)
912
913 default_r_c = db(2)*cube%spacing(2)/m_two
914 call get_cutoff(namespace, default_r_c, r_c)
915
916 ! store the fourier transform of the Coulomb interaction
917 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
918 fft_coulb_fs = m_zero
919 temp(1:2) = m_two*m_pi/(db(1:2)*cube%spacing(1:2))
920
921 ! First, the term ix = 0 => gx = 0.
922 fft_coulb_fs(1, 1, 1) = -m_four * r_c * (log(r_c)-m_one)
923 do iy = 2, cube%fs_n_global(2)
924 ixx(2) = pad_feq(iy, db(2), .true.)
925 gy = temp(2)*ixx(2)
926 fft_coulb_fs(1, iy, 1) = -m_four * poisson_cutoff_intcoslog(r_c, gy, m_one) * weight
927 end do
928
929 do ix = 2, cube%fs_n_global(1)
930 ixx(1) = pad_feq(ix, db(1), .true.)
931 gx = temp(1)*ixx(1)
932 do iy = 1, cube%fs_n_global(2)
933 ixx(2) = pad_feq(iy, db(2), .true.)
934 gy = temp(2)*ixx(2)
935 fft_coulb_fs(ix, iy, 1) = poisson_cutoff_2d_1d(gy, gx, r_c) * weight
936 end do
937 end do
938
939 call coulb%dset_op(cube, op_move = fft_coulb_fs)
940
941 safe_deallocate_a(fft_coulb_fs)
942
944 end subroutine poisson_fft_build_2d_1d
945 !-----------------------------------------------------------------
946
947
948 !-----------------------------------------------------------------
950 subroutine poisson_fft_build_2d_2d(cube, coulb)
951 type(cube_t), intent(in) :: cube
952 type(fourier_space_op_t), intent(inout) :: coulb
953
954 integer :: ix, iy, ixx(2), db(2)
955 real(real64) :: temp(2), vec, weight
956 real(real64), allocatable :: fft_coulb_FS(:,:,:)
957
959
960 assert(abs(coulb%mu) < m_epsilon)
961 ! Full range hybrids weight
962 weight = m_one
963 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
964
965 db(1:2) = cube%rs_n_global(1:2)
966
967 ! store the fourier transform of the Coulomb interaction
968 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
969 fft_coulb_fs = m_zero
970 temp(1:2) = m_two*m_pi/(db(1:2)*cube%spacing(1:2))
971
972 do iy = 1, cube%fs_n_global(2)
973 ixx(2) = pad_feq(iy, db(2), .true.)
974 do ix = 1, cube%fs_n_global(1)
975 ixx(1) = pad_feq(ix, db(1), .true.)
976 vec = sqrt((temp(1) * ixx(1))**2 + (temp(2) * ixx(2))**2)
977 if (vec > m_zero) fft_coulb_fs(ix, iy, 1) = m_two * m_pi / vec * weight
978 end do
979 end do
980
981 call coulb%dset_op(cube, op_move = fft_coulb_fs)
982
983 safe_deallocate_a(fft_coulb_fs)
985 end subroutine poisson_fft_build_2d_2d
986 !-----------------------------------------------------------------
987
988
989 !-----------------------------------------------------------------
990 subroutine poisson_fft_build_1d_1d(cube, coulb, poisson_soft_coulomb_param)
991 type(cube_t), intent(in) :: cube
992 type(fourier_space_op_t), intent(inout) :: coulb
993 real(real64), intent(in) :: poisson_soft_coulomb_param
994
995 integer :: ix, ixx
996 real(real64) :: g, weight
997 real(real64), allocatable :: fft_coulb_fs(:, :, :)
998
1000
1001 assert(abs(coulb%mu) < m_epsilon)
1002 ! Full range hybrids weight
1003 weight = m_one
1004 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
1005
1006 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
1007 fft_coulb_fs = m_zero
1008
1009 ! Fourier transform of Soft Coulomb interaction.
1010 do ix = 1, cube%fs_n_global(1)
1011 ixx = pad_feq(ix, cube%rs_n_global(1), .true.)
1012 g = (ixx + coulb%qq(1))*m_two*m_pi/abs(cube%latt%rlattice(1,1))
1013 if (abs(g) > tol_vanishing_q) then
1014 fft_coulb_fs(ix, 1, 1) = m_two * loct_bessel_k0(poisson_soft_coulomb_param*abs(g)) * weight
1015 else
1016 fft_coulb_fs(ix, 1, 1) = coulb%singularity * m_two * weight
1017 end if
1018 end do
1019
1020 call coulb%dset_op(cube, op_move = fft_coulb_fs)
1021 safe_deallocate_a(fft_coulb_fs)
1022
1024 end subroutine poisson_fft_build_1d_1d
1025 !-----------------------------------------------------------------
1026
1027
1028 !-----------------------------------------------------------------
1029 subroutine poisson_fft_build_1d_0d(namespace, cube, coulb, poisson_soft_coulomb_param)
1030 type(namespace_t), intent(in) :: namespace
1031 type(cube_t), intent(in) :: cube
1032 type(fourier_space_op_t), intent(inout) :: coulb
1033 real(real64), intent(in) :: poisson_soft_coulomb_param
1034
1035 integer :: box(1), ixx(1), ix
1036 real(real64) :: temp(1), g, r_c, default_r_c, weight
1037 real(real64), allocatable :: fft_coulb_fs(:, :, :)
1038
1039 push_sub(poisson_fft_build_1d_0d)
1040
1041 assert(abs(coulb%mu) < m_epsilon)
1042 ! Full range hybrids weight
1043 weight = m_one
1044 if(coulb%alpha > m_epsilon) weight = weight * coulb%alpha
1046 box(1:1) = cube%rs_n_global(1:1)
1047
1048 default_r_c = box(1)*cube%spacing(1)/m_two
1049 call get_cutoff(namespace, default_r_c, r_c)
1050
1051 safe_allocate(fft_coulb_fs(1:cube%fs_n_global(1), 1:cube%fs_n_global(2), 1:cube%fs_n_global(3)))
1052 fft_coulb_fs = m_zero
1053 temp(1:1) = m_two*m_pi/(box(1:1)*cube%spacing(1:1))
1054
1055 ! Fourier transform of Soft Coulomb interaction.
1056 do ix = 1, cube%fs_n_global(1)
1057 ixx(1) = pad_feq(ix, box(1), .true.)
1058 g = temp(1)*ixx(1)
1059 fft_coulb_fs(ix, 1, 1) = poisson_cutoff_1d_0d(g, poisson_soft_coulomb_param, r_c) * weight
1060 end do
1061
1062 call coulb%dset_op(cube, op_move = fft_coulb_fs)
1063 safe_deallocate_a(fft_coulb_fs)
1064
1066 end subroutine poisson_fft_build_1d_0d
1067 !-----------------------------------------------------------------
1068
1069
1070 !-----------------------------------------------------------------
1071 subroutine poisson_fft_end(this)
1072 type(poisson_fft_t), intent(inout) :: this
1073
1074 push_sub(poisson_fft_end)
1075
1076 call this%coulb%end()
1077
1078 pop_sub(poisson_fft_end)
1079 end subroutine poisson_fft_end
1080
1081#include "undef.F90"
1082#include "real.F90"
1083#include "poisson_fft_inc.F90"
1084#include "undef.F90"
1085#include "complex.F90"
1086#include "poisson_fft_inc.F90"
1087
1088#include "undef.F90"
1089#include "real32.F90"
1090#include "poisson_fft_inc.F90"
1091#include "undef.F90"
1092#include "complex32.F90"
1093#include "poisson_fft_inc.F90"
1094
1095
1096end module poisson_fft_oct_m
1097
1098!! Local Variables:
1099!! mode: f90
1100!! coding: utf-8
1101!! End:
Some operations may be done for one spline-function, or for an array of them.
Definition: splines.F90:179
double hypot(double __x, double __y) __attribute__((__nothrow__
double log(double __x) __attribute__((__nothrow__
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:120
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...
Definition: fft.F90:1116
pure integer function, public pad_feq(ii, nn, mode)
convert between array index and G-vector
Definition: fft.F90:975
pure subroutine, public fft_gg_transform(gg_in, temp, periodic_dim, latt, qq, gg, modg2)
Convert FFT grid index into the Cartesian reciprocal-space vector .
Definition: fft.F90:1071
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_huge
Definition: global.F90:218
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_four
Definition: global.F90:204
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
real(real64), parameter, public m_fourth
Definition: global.F90:209
real(real64), parameter, public m_epsilon
Definition: global.F90:216
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
pure real(real64) function, dimension(1:3), public dcross_product(a, b)
Definition: math.F90:1909
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
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, public dpoisson_fft_solve_batch(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm, pot_buffer, rho_buffer, count)
subroutine poisson_fft_build_3d_2d(namespace, cube, coulb)
C. A. Rozzi et al., Phys. Rev. B 73, 205119 (2006), Table I.
real(real64) function poisson_fft_singularity_3d(coulb)
Define the singularity correction for |q+G| = 0, for the 3D Coulomb kernel.
integer, parameter, public poisson_fft_kernel_nocut
subroutine, public spoisson_fft_solve_batch(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm, pot_buffer, rho_buffer, count)
subroutine, public spoisson_fft_solve(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm)
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, public cpoisson_fft_solve_batch(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm, pot_buffer, rho_buffer, count)
subroutine, public cpoisson_fft_solve(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm)
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)
Compute the Coulomb kernel in reciprocal space, for a 3D FFT grid.
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
subroutine, public zpoisson_fft_solve_batch(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm, pot_buffer, rho_buffer, count)
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)
Definition: splines.F90:413
real(real64) function, public spline_eval(spl, x)
Definition: splines.F90:441
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
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
type(xc_cam_t), parameter, public cam_null
All CAM parameters set to zero.
Definition: xc_cam.F90:151
Definition of a Fourier Space Coulomb Kernel.
the basic spline datatype
Definition: splines.F90:156
int true(void)