Octopus
poisson.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2011 M. Marques, A. Castro, A. Rubio,
2!! G. Bertsch, M. Oliveira
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 poisson_oct_m
23 use accel_oct_m
24 use batch_oct_m
27 use cube_oct_m
29 use debug_oct_m
31 use fft_oct_m
33 use global_oct_m
34 use index_oct_m
35 use, intrinsic :: iso_fortran_env
38 use math_oct_m
39 use mesh_oct_m
43 use mpi_oct_m
46#ifdef HAVE_OPENMP
47 use omp_lib
48#endif
50 use parser_oct_m
61 use space_oct_m
64 use types_oct_m
67 use xc_cam_oct_m
68
69 implicit none
70
71 private
72 public :: &
73 poisson_t, &
95
96 integer, public, parameter :: &
97 POISSON_DIRECT_SUM = -1, &
98 poisson_fft = 0, &
99 poisson_cg = 5, &
101 poisson_multigrid = 7, &
102 poisson_isf = 8, &
103 poisson_psolver = 10, &
104 poisson_no = -99, &
105 poisson_null = -999
106
107 type poisson_t
108 private
109 type(derivatives_t), pointer, public :: der
110 integer, public :: method = poisson_null
111 integer, public :: kernel
112 type(cube_t), public :: cube
113 type(mesh_cube_parallel_map_t), public :: mesh_cube_map
114 type(poisson_mg_solver_t) :: mg
115 type(poisson_fft_t), public :: fft_solver
116 real(real64), public :: poisson_soft_coulomb_param
117 logical :: all_nodes_default
118 type(poisson_corr_t) :: corrector
119 type(poisson_isf_t) :: isf_solver
120 type(poisson_psolver_t) :: psolver_solver
121 type(poisson_no_t) :: no_solver
122 integer :: nslaves
123 logical, public :: is_dressed = .false.
124 type(photon_mode_t), public :: photons
125#ifdef HAVE_MPI
126 type(MPI_Comm) :: intercomm
127 type(mpi_grp_t) :: local_grp
128 logical :: root
129#endif
130 end type poisson_t
131
132 integer, parameter :: &
133 CMD_FINISH = 1, &
135
136contains
137
138 !-----------------------------------------------------------------
139 subroutine poisson_init(this, namespace, space, der, mc, stencil, qtot, label, solver, verbose, force_serial, &
140 force_cmplx, fft_batch_size)
141 type(poisson_t), intent(inout) :: this
142 class(space_t), intent(in) :: space
143 type(namespace_t), intent(in) :: namespace
144 type(derivatives_t), target, intent(in) :: der
145 type(multicomm_t), intent(in) :: mc
146 type(stencil_t), intent(in) :: stencil
147 real(real64), optional, intent(in) :: qtot
148 character(len=*), optional, intent(in) :: label
149 integer, optional, intent(in) :: solver
150 logical, optional, intent(in) :: verbose
151 logical, optional, intent(in) :: force_serial
152 logical, optional, intent(in) :: force_cmplx
153 integer, optional, intent(in) :: fft_batch_size
154
155 logical :: need_cube, isf_data_is_parallel
156 integer :: default_solver, default_kernel, box(space%dim), fft_type, fft_library, fft_bs
157 real(real64) :: fft_alpha
158 character(len=60) :: str
159
160 ! Make sure we do not try to initialize an already initialized solver
161 assert(this%method == poisson_null)
162
163 push_sub(poisson_init)
164
165 if (optional_default(verbose,.true.)) then
166 str = "Hartree"
167 if (present(label)) str = trim(label)
168 call messages_print_with_emphasis(msg=trim(str), namespace=namespace)
169 end if
170
171 this%nslaves = 0
172 this%der => der
173
174 !%Variable DressedOrbitals
175 !%Type logical
176 !%Default false
177 !%Section Hamiltonian::Poisson
178 !%Description
179 !% Allows for the calculation of coupled elecron-photon problems
180 !% by applying the dressed orbital approach. Details can be found in
181 !% https://arxiv.org/abs/1812.05562
182 !% At the moment, N electrons in d (<=3) spatial dimensions, coupled
183 !% to one photon mode can be described. The photon mode is included by
184 !% raising the orbital dimension to d+1 and changing the particle interaction
185 !% kernel and the local potential, where the former is included automatically,
186 !% but the latter needs to by added by hand as a user_defined_potential!
187 !% Coordinate 1-d: electron; coordinate d+1: photon.
188 !%End
189 call parse_variable(namespace, 'DressedOrbitals', .false., this%is_dressed)
190 call messages_print_var_value('DressedOrbitals', this%is_dressed, namespace=namespace)
191 if (this%is_dressed) then
192 assert(present(qtot))
193 call messages_experimental('Dressed Orbitals', namespace=namespace)
194 assert(qtot > m_zero)
195 call photon_mode_init(this%photons, namespace, der%dim-1)
196 call photon_mode_set_n_electrons(this%photons, qtot)
197 if(.not.allocated(this%photons%pol_dipole)) then
198 call photon_mode_compute_dipoles(this%photons, der%mesh)
199 end if
200 if (this%photons%nmodes > 1) then
201 call messages_not_implemented('DressedOrbitals for more than one photon mode', namespace=namespace)
202 end if
203 end if
205 this%all_nodes_default = .false.
206#ifdef HAVE_MPI
207 if (.not. optional_default(force_serial, .false.)) then
208 !%Variable ParallelizationPoissonAllNodes
209 !%Type logical
210 !%Default true
211 !%Section Execution::Parallelization
212 !%Description
213 !% When running in parallel, this variable selects whether the
214 !% Poisson solver should divide the work among all nodes or only
215 !% among the parallelization-in-domains groups.
216 !%End
218 call parse_variable(namespace, 'ParallelizationPoissonAllNodes', .true., this%all_nodes_default)
219 end if
220#endif
221
222 !%Variable PoissonSolver
223 !%Type integer
224 !%Section Hamiltonian::Poisson
225 !%Description
226 !% Defines which method to use to solve the Poisson equation. Some incompatibilities apply depending on
227 !% dimensionality, periodicity, etc.
228 !% For a comparison of the accuracy and performance of the methods in Octopus, see P Garcia-Risue&ntilde;o,
229 !% J Alberdi-Rodriguez <i>et al.</i>, <i>J. Comp. Chem.</i> <b>35</b>, 427-444 (2014)
230 !% or <a href=http://arxiv.org/abs/1211.2092>arXiV</a>.
231 !% Defaults:
232 !% <br> 1D and 2D: <tt>fft</tt>.
233 !% <br> 3D: <tt>cg_corrected</tt> if curvilinear, <tt>isf</tt> if not periodic, <tt>fft</tt> if periodic.
234 !% <br> Dressed orbitals: <tt>direct_sum</tt>.
235 !%Option NoPoisson -99
236 !% Do not use a Poisson solver at all.
237 !%Option direct_sum -1
238 !% Direct evaluation of the Hartree potential (only for finite systems).
239 !%Option fft 0
240 !% The Poisson equation is solved using FFTs. A cutoff technique
241 !% for the Poisson kernel is selected so the proper boundary
242 !% conditions are imposed according to the periodicity of the
243 !% system. This can be overridden by the <tt>PoissonFFTKernel</tt>
244 !% variable. To choose the FFT library use <tt>FFTLibrary</tt>
245 !%Option cg 5
246 !% Conjugate gradients.
247 !%Option cg_corrected 6
248 !% Conjugate gradients, corrected for boundary conditions (only for finite systems).
249 !%Option multigrid 7
250 !% Multigrid method.
251 !%Option isf 8
252 !% Interpolating Scaling Functions Poisson solver (only for finite systems).
253 !%Option psolver 10
254 !% Solver based on Interpolating Scaling Functions as implemented in the PSolver library.
255 !% Parallelization in k-points requires <tt>PoissonSolverPSolverParallelData</tt> = no.
256 !% Requires the PSolver external library.
257 !%End
258
259 default_solver = poisson_fft
260
261 if (space%dim == 3 .and. .not. space%is_periodic()) default_solver = poisson_isf
262
263#ifdef HAVE_CUDA
264 if(accel_is_enabled()) default_solver = poisson_fft
265#endif
266
267 if (space%dim > 3) default_solver = poisson_no ! Kernel for higher dimensions is not implemented.
268
269 if (der%mesh%use_curvilinear) then
270 select case (space%dim)
271 case (1)
272 default_solver = poisson_direct_sum
273 case (2)
274 default_solver = poisson_direct_sum
275 case (3)
276 default_solver = poisson_multigrid
277 end select
278 end if
279
280 if (this%is_dressed) default_solver = poisson_direct_sum
281
282 if (.not. present(solver)) then
283 call parse_variable(namespace, 'PoissonSolver', default_solver, this%method)
284 else
285 this%method = solver
286 end if
287 if (.not. varinfo_valid_option('PoissonSolver', this%method)) call messages_input_error(namespace, 'PoissonSolver')
288 if (optional_default(verbose, .true.)) then
289 select case (this%method)
290 case (poisson_direct_sum)
291 str = "direct sum"
292 case (poisson_fft)
293 str = "fast Fourier transform"
294 case (poisson_cg)
295 str = "conjugate gradients"
297 str = "conjugate gradients, corrected"
298 case (poisson_multigrid)
299 str = "multigrid"
300 case (poisson_isf)
301 str = "interpolating scaling functions"
302 case (poisson_psolver)
303 str = "interpolating scaling functions (from BigDFT)"
304 case (poisson_no)
305 str = "no Poisson solver - Hartree set to 0"
306 end select
307 write(message(1),'(a,a,a)') "The chosen Poisson solver is '", trim(str), "'"
308 call messages_info(1, namespace=namespace)
309 end if
310
311 if (space%dim > 3 .and. this%method /= poisson_no) then
312 call messages_input_error(namespace, 'PoissonSolver', 'Currently no Poisson solver is available for Dimensions > 3')
313 end if
314
315 fft_bs = optional_default(fft_batch_size, 1)
316 assert(fft_bs > 0)
317
318 if (this%method /= poisson_fft) then
319 this%kernel = poisson_fft_kernel_none
320 else
321
322 ! Documentation in cube.F90
323 call parse_variable(namespace, 'FFTLibrary', fftlib_fftw, fft_library)
324
325 !%Variable PoissonFFTKernel
326 !%Type integer
327 !%Section Hamiltonian::Poisson
328 !%Description
329 !% Defines which kernel is used to impose the correct boundary
330 !% conditions when using FFTs to solve the Poisson equation. The
331 !% default is selected depending on the dimensionality and
332 !% periodicity of the system:
333 !% <br>In 1D, <tt>spherical</tt> if finite, <tt>fft_nocut</tt> if periodic.
334 !% <br>In 2D, <tt>spherical</tt> if finite, <tt>cylindrical</tt> if 1D-periodic, <tt>fft_nocut</tt> if 2D-periodic.
335 !% <br>In 3D, <tt>spherical</tt> if finite, <tt>cylindrical</tt> if 1D-periodic, <tt>planar</tt> if 2D-periodic,
336 !% <tt>fft_nocut</tt> if 3D-periodic.
337 !% See C. A. Rozzi et al., <i>Phys. Rev. B</i> <b>73</b>, 205119 (2006) for 3D implementation and
338 !% A. Castro et al., <i>Phys. Rev. B</i> <b>80</b>, 033102 (2009) for 2D implementation.
339 !%Option spherical 0
340 !% FFTs using spherical cutoff (in 2D or 3D).
341 !%Option cylindrical 1
342 !% FFTs using cylindrical cutoff (in 2D or 3D).
343 !%Option planar 2
344 !% FFTs using planar cutoff (in 3D).
345 !%Option fft_nocut 3
346 !% FFTs without using a cutoff (for fully periodic systems).
347 !%Option multipole_correction 4
348 !% The boundary conditions are imposed by using a multipole expansion. Only appropriate for finite systems.
349 !% Further specification occurs with variables <tt>PoissonSolverBoundaries</tt> and <tt>PoissonSolverMaxMultipole</tt>.
350 !%End
351
352 select case (space%dim)
353 case (1)
354 if (.not. space%is_periodic()) then
355 default_kernel = poisson_fft_kernel_sph
356 else
357 default_kernel = poisson_fft_kernel_nocut
358 end if
359 case (2)
360 if (space%periodic_dim == 2) then
361 default_kernel = poisson_fft_kernel_nocut
362 else if (space%is_periodic()) then
363 default_kernel = space%periodic_dim
364 else
365 default_kernel = poisson_fft_kernel_sph
366 end if
367 case (3)
368 default_kernel = space%periodic_dim
369 end select
370
371 call parse_variable(namespace, 'PoissonFFTKernel', default_kernel, this%kernel)
372 if (.not. varinfo_valid_option('PoissonFFTKernel', this%kernel)) call messages_input_error(namespace, 'PoissonFFTKernel')
373
374 if (optional_default(verbose,.true.)) then
375 call messages_print_var_option("PoissonFFTKernel", this%kernel, namespace=namespace)
376 end if
377
378 ! the multipole correction kernel does not work on GPUs
379 if(this%kernel == poisson_fft_kernel_corrected .and. fft_default_lib == fftlib_accel) then
381 message(1) = 'PoissonFFTKernel=multipole_correction is not supported on GPUs'
382 message(2) = 'Using FFTW to compute the FFTs on the CPU'
383 call messages_info(2, namespace=namespace)
384 end if
385
386 end if
387
388 !We assume the developer knows what he is doing by providing the solver option
389 if (.not. present(solver)) then
390 if (space%is_periodic() .and. this%method == poisson_direct_sum) then
391 message(1) = 'A periodic system may not use the direct_sum Poisson solver.'
392 call messages_fatal(1, namespace=namespace)
393 end if
394
395 if (space%is_periodic() .and. this%method == poisson_cg_corrected) then
396 message(1) = 'A periodic system may not use the cg_corrected Poisson solver.'
397 call messages_fatal(1, namespace=namespace)
398 end if
399
400 select case (space%dim)
401 case (1)
402
403 select case (space%periodic_dim)
404 case (0)
405 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
406 message(1) = 'A finite 1D system may only use fft or direct_sum Poisson solvers.'
407 call messages_fatal(1, namespace=namespace)
408 end if
409 case (1)
410 if (this%method /= poisson_fft) then
411 message(1) = 'A periodic 1D system may only use the fft Poisson solver.'
412 call messages_fatal(1, namespace=namespace)
413 end if
414 end select
415
416 if (der%mesh%use_curvilinear .and. this%method /= poisson_direct_sum) then
417 message(1) = 'If curvilinear coordinates are used in 1D, then the only working'
418 message(2) = 'Poisson solver is direct_sum.'
419 call messages_fatal(2, namespace=namespace)
420 end if
421
422 case (2)
423
424 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
425 message(1) = 'A 2D system may only use fft or direct_sum solvers.'
426 call messages_fatal(1, namespace=namespace)
427 end if
428
429 if (der%mesh%use_curvilinear .and. (this%method /= poisson_direct_sum)) then
430 message(1) = 'If curvilinear coordinates are used in 2D, then the only working'
431 message(2) = 'Poisson solver is direct_sum.'
432 call messages_fatal(2, namespace=namespace)
433 end if
434
435 case (3)
436
437 if (space%is_periodic() .and. this%method == poisson_isf) then
438 call messages_write('The ISF solver can only be used for finite systems.')
439 call messages_fatal()
440 end if
441
442 if (space%is_periodic() .and. this%method == poisson_fft .and. &
443 this%kernel /= space%periodic_dim .and. this%kernel >= 0 .and. this%kernel <= 3) then
444 write(message(1), '(a,i1,a)')'The system is periodic in ', space%periodic_dim ,' dimension(s),'
445 write(message(2), '(a,i1,a)')'but Poisson solver is set for ', this%kernel, ' dimensions.'
446 call messages_warning(2, namespace=namespace)
447 end if
448
449 if (space%is_periodic() .and. this%method == poisson_fft .and. this%kernel == poisson_fft_kernel_corrected) then
450 write(message(1), '(a,i1,a)')'PoissonFFTKernel = multipole_correction cannot be used for periodic systems.'
451 call messages_fatal(1, namespace=namespace)
452 end if
453
454 if (der%mesh%use_curvilinear .and. .not. any(this%method == [poisson_cg_corrected, poisson_multigrid])) then
455 message(1) = 'If curvilinear coordinates are used, then the only working'
456 message(2) = 'Poisson solvers are cg_corrected and multigrid.'
457 call messages_fatal(2, namespace=namespace)
458 end if
459 if (der%mesh%use_curvilinear .and. this%method == poisson_multigrid .and. accel_is_enabled()) then
460 call messages_not_implemented('Multigrid Poisson solver with curvilinear coordinates on GPUs')
461 end if
462
463 select type (box => der%mesh%box)
464 type is (box_minimum_t)
465 if (this%method == poisson_cg_corrected) then
466 message(1) = 'When using the "minimum" box shape and the "cg_corrected"'
467 message(2) = 'Poisson solver, we have observed "sometimes" some non-'
468 message(3) = 'negligible error. You may want to check that the "fft" or "cg"'
469 message(4) = 'solver are providing, in your case, the same results.'
470 call messages_warning(4, namespace=namespace)
471 end if
472 end select
473
474 end select
475 end if
476
477 if (this%method == poisson_psolver) then
478#if !(defined HAVE_PSOLVER)
479 message(1) = "The PSolver Poisson solver cannot be used since the code was not compiled with the PSolver library."
480 call messages_fatal(1, namespace=namespace)
481#endif
482 end if
483
484 if (optional_default(verbose,.true.)) then
485 call messages_print_with_emphasis(namespace=namespace)
486 end if
487
488 ! Now that we know the method, we check if we need a cube and its dimensions
489 need_cube = .false.
490 fft_type = fft_real
491 if (optional_default(force_cmplx, .false.)) fft_type = fft_complex
492
493 if (this%method == poisson_isf .or. this%method == poisson_psolver) then
494 fft_type = fft_none
495 box(:) = der%mesh%idx%ll(:)
496 need_cube = .true.
497 end if
498
499 if (this%method == poisson_psolver .and. multicomm_have_slaves(mc)) then
500 call messages_not_implemented('Task parallelization with PSolver Poisson solver', namespace=namespace)
501 end if
502
504 ! Documentation in poisson_psolver.F90
505 call parse_variable(namespace, 'PoissonSolverPSolverParallelData', .true., isf_data_is_parallel)
506 if (this%method == poisson_psolver .and. isf_data_is_parallel) then
507 call messages_not_implemented("k-point parallelization with PSolver library and", namespace=namespace)
508 call messages_not_implemented("PoissonSolverPSolverParallelData = yes", namespace=namespace)
509 end if
510 if (this%method == poisson_fft .and. fft_library == fftlib_pfft) then
511 call messages_not_implemented("k-point parallelization with PFFT library for", namespace=namespace)
512 call messages_not_implemented("PFFT library for Poisson solver", namespace=namespace)
513 end if
514 end if
515
516 if (this%method == poisson_fft) then
517
518 need_cube = .true.
519
520 !%Variable DoubleFFTParameter
521 !%Type float
522 !%Default 2.0
523 !%Section Mesh::FFTs
524 !%Description
525 !% For solving the Poisson equation in Fourier space, and for applying the local potential
526 !% in Fourier space, an auxiliary cubic mesh is built. This mesh will be larger than
527 !% the circumscribed cube of the usual mesh by a factor <tt>DoubleFFTParameter</tt>. See
528 !% the section that refers to Poisson equation, and to the local potential for details
529 !% [the default value of two is typically good].
530 !%End
531 call parse_variable(namespace, 'DoubleFFTParameter', m_two, fft_alpha)
532 if (fft_alpha < m_one .or. fft_alpha > m_three) then
533 write(message(1), '(a,f12.5,a)') "Input: '", fft_alpha, &
534 "' is not a valid DoubleFFTParameter"
535 message(2) = '1.0 <= DoubleFFTParameter <= 3.0'
536 call messages_fatal(2, namespace=namespace)
537 end if
538
539 if (space%dim /= 3 .and. fft_library == fftlib_pfft) then
540 call messages_not_implemented('PFFT support for dimensionality other than 3', namespace=namespace)
541 end if
542
543 select case (space%dim)
544
545 case (1)
546 select case (this%kernel)
548 call mesh_double_box(space, der%mesh, fft_alpha, box)
550 box = der%mesh%idx%ll
551 end select
552
553 case (2)
554 select case (this%kernel)
556 call mesh_double_box(space, der%mesh, fft_alpha, box)
557 box(1:2) = maxval(box)
559 call mesh_double_box(space, der%mesh, fft_alpha, box)
561 box(:) = der%mesh%idx%ll(:)
562 end select
563
564 case (3)
565 select case (this%kernel)
567 call mesh_double_box(space, der%mesh, fft_alpha, box)
568 box(:) = maxval(box)
570 call mesh_double_box(space, der%mesh, fft_alpha, box)
571 box(2) = maxval(box(2:3)) ! max of finite directions
572 box(3) = maxval(box(2:3)) ! max of finite directions
574 box(:) = der%mesh%idx%ll(:)
576 call mesh_double_box(space, der%mesh, fft_alpha, box)
577 end select
578
579 end select
580
581 end if
582
583 ! Solvers that cannot transform a whole batch at once are applied one function at a time
584 ! (see X(poisson_solve_batch)) and do not need a batched cube.
585 if (.not. poisson_is_batch_capable(this)) fft_bs = 1
586
587 ! Create the cube
588 if (need_cube) then
589 call cube_init(this%cube, box, namespace, space, der%mesh%spacing, &
590 der%mesh%coord_system, fft_type = fft_type, &
591 need_partition=.not.der%mesh%parallel_in_domains, &
592 batch_size=fft_bs)
593 call cube_init_cube_map(this%cube, der%mesh)
594 if (this%cube%parallel_in_domains .and. this%method == poisson_fft) then
595 call mesh_cube_parallel_map_init(this%mesh_cube_map, der%mesh, this%cube)
596 end if
597 end if
598
599 if (this%is_dressed .and. .not. this%method == poisson_direct_sum) then
600 write(message(1), '(a)')'Dressed Orbital calculation currently only working with direct sum Poisson solver.'
601 call messages_fatal(1, namespace=namespace)
602 end if
603
604 call poisson_kernel_init(this, namespace, space, mc, stencil)
605
606 pop_sub(poisson_init)
607 end subroutine poisson_init
608
609 !-----------------------------------------------------------------
610 subroutine poisson_end(this)
611 type(poisson_t), intent(inout) :: this
612
613 logical :: has_cube
614
615 push_sub(poisson_end)
616
617 has_cube = .false.
618
619 select case (this%method)
620 case (poisson_fft)
621 call poisson_fft_end(this%fft_solver)
622 if (this%kernel == poisson_fft_kernel_corrected) call poisson_corrections_end(this%corrector)
623 has_cube = .true.
624
626 call poisson_cg_end()
627 call poisson_corrections_end(this%corrector)
628
629 case (poisson_multigrid)
630 call poisson_multigrid_end(this%mg)
631
632 case (poisson_isf)
633 call poisson_isf_end(this%isf_solver)
634 has_cube = .true.
635
636 case (poisson_psolver)
637 call poisson_psolver_end(this%psolver_solver)
638 has_cube = .true.
639
640 case (poisson_no)
641 call poisson_no_end(this%no_solver)
642
643 end select
644 this%method = poisson_null
645
646 if (has_cube) then
647 if (this%cube%parallel_in_domains) then
648 call mesh_cube_parallel_map_end(this%mesh_cube_map)
649 end if
650 call cube_end(this%cube)
651 end if
652
653 if (this%is_dressed) then
654 call photon_mode_end(this%photons)
655 end if
656 this%is_dressed = .false.
657
658 pop_sub(poisson_end)
659 end subroutine poisson_end
660
661 !-----------------------------------------------------------------
662
663 subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
664 type(poisson_t), intent(in) :: this
665 type(namespace_t), intent(in) :: namespace
666 complex(real64), contiguous, intent(inout) :: pot(:)
667 complex(real64), contiguous, intent(in) :: rho(:)
668 logical, optional, intent(in) :: all_nodes
669 type(fourier_space_op_t), optional, intent(in) :: kernel
670
671 real(real64), allocatable :: aux1(:), aux2(:)
672 type(derivatives_t), pointer :: der
673 logical :: all_nodes_value
674 integer :: ip
675
676
677 der => this%der
678
680
681 call profiling_in('POISSON_RE_IM_SOLVE')
682
683 if (present(kernel) .and. der%periodic_dim>0) then
684 assert(.not. any(abs(kernel%qq(:))>1e-8_real64))
685 end if
686
687 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
688
689 safe_allocate(aux1(1:der%mesh%np))
690 safe_allocate(aux2(1:der%mesh%np))
691 ! first the real part
692 aux1(1:der%mesh%np) = real(rho(1:der%mesh%np), real64)
693 aux2(1:der%mesh%np) = real(pot(1:der%mesh%np), real64)
694 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
695 pot(1:der%mesh%np) = aux2(1:der%mesh%np)
696
697 ! now the imaginary part
698 aux1(1:der%mesh%np) = aimag(rho(1:der%mesh%np))
699 aux2(1:der%mesh%np) = aimag(pot(1:der%mesh%np))
700 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
701 !$omp parallel do
702 do ip = 1, der%mesh%np
703 pot(ip) = pot(ip) + m_zi*aux2(ip)
704 end do
705 !$omp end parallel do
706
707 safe_deallocate_a(aux1)
708 safe_deallocate_a(aux2)
709
710 call profiling_out('POISSON_RE_IM_SOLVE')
711
714
715 !-----------------------------------------------------------------
716
722 subroutine zpoisson_solve_real_and_imag_separately_batch(this, namespace, pot, rho, kernel)
723 type(poisson_t), intent(in) :: this
724 type(namespace_t), intent(in) :: namespace
725 complex(real64), contiguous, intent(out) :: pot(:, :)
726 complex(real64), contiguous, intent(in) :: rho(:, :)
727 type(fourier_space_op_t), optional, intent(in) :: kernel
728
729 real(real64), allocatable :: rwork(:, :), pwork(:, :)
730
732 call profiling_in('POISSON_RE_IM_SOLVE_BATCH')
733
734 if (present(kernel) .and. this%der%periodic_dim>0) then
735 assert(.not. any(abs(kernel%qq(:))>1e-8_real64))
736 end if
737
738 safe_allocate(rwork(1:size(rho, 1), 1:size(rho, 2)))
739 safe_allocate(pwork(1:size(pot, 1), 1:size(pot, 2)))
740
741 ! first the real part
742 rwork = real(rho, real64)
743 call dpoisson_solve_batch(this, namespace, pwork, rwork, kernel=kernel)
744 pot = pwork
745
746 ! now the imaginary part
747 rwork = aimag(rho)
748 call dpoisson_solve_batch(this, namespace, pwork, rwork, kernel=kernel)
749 pot = pot + m_zi*pwork
750
751 safe_deallocate_a(rwork)
752 safe_deallocate_a(pwork)
753
754 call profiling_out('POISSON_RE_IM_SOLVE_BATCH')
757
758 !-----------------------------------------------------------------
759
761 subroutine zpoisson_solve_real_and_imag_separately_accel(this, namespace, pot_buffer, rho_buffer, kernel, count)
762 type(poisson_t), intent(in) :: this
763 type(namespace_t), intent(in) :: namespace
764 type(accel_mem_t), intent(inout) :: pot_buffer
765 type(accel_mem_t), intent(in) :: rho_buffer
766 type(fourier_space_op_t), optional, intent(in) :: kernel
767 integer, optional, intent(in) :: count
768
769 type(accel_mem_t) :: re_in, im_in, re_out, im_out
770 type(accel_kernel_t), save :: kernel_split, kernel_merge
771 integer(int64) :: gsizes(3), bsizes(3)
772 integer :: np, count_, np_tot
773
775 call profiling_in('POISSON_RE_IM_ACCEL')
776
777 if (present(kernel)) then
778 assert(.not. any(abs(kernel%qq(:)) > 1e-8_real64))
779 end if
780
781 count_ = optional_default(count, 1)
782 np = this%der%mesh%np
783 np_tot = np * count_
784
785 call accel_create_buffer(re_in, accel_mem_read_write, type_float, int(np, int64) * count_)
786 call accel_create_buffer(im_in, accel_mem_read_write, type_float, int(np, int64) * count_)
787 call accel_create_buffer(re_out, accel_mem_read_write, type_float, int(np, int64) * count_)
788 call accel_create_buffer(im_out, accel_mem_read_write, type_float, int(np, int64) * count_)
789
790 ! split rho (complex) into its real and imaginary parts
791 call accel_kernel_start_call(kernel_split, 'split.cu', 'split_complex<double>')
792 call accel_set_kernel_arg(kernel_split, 0, np_tot)
793 call accel_set_kernel_arg(kernel_split, 1, rho_buffer)
794 call accel_set_kernel_arg(kernel_split, 2, 0)
795 call accel_set_kernel_arg(kernel_split, 3, re_in)
796 call accel_set_kernel_arg(kernel_split, 4, 0)
797 call accel_set_kernel_arg(kernel_split, 5, im_in)
798 call accel_set_kernel_arg(kernel_split, 6, 0)
799 call accel_grid_size_extend_dim(int(np_tot, int64), 1_int64, gsizes, bsizes, kernel_split)
800 call accel_kernel_run(kernel_split, gsizes, bsizes)
801
802 ! solve the real and imaginary parts on the real cube with the batched solver.
803 call dpoisson_solve_batch(this, namespace, pot_buffer=re_out, rho_buffer=re_in, kernel=kernel, count=count_)
804 call dpoisson_solve_batch(this, namespace, pot_buffer=im_out, rho_buffer=im_in, kernel=kernel, count=count_)
805
806 ! recombine pot = re_out + i*im_out
807 call accel_kernel_start_call(kernel_merge, 'split.cu', 'merge_complex<double>')
808 call accel_set_kernel_arg(kernel_merge, 0, np_tot)
809 call accel_set_kernel_arg(kernel_merge, 1, re_out)
810 call accel_set_kernel_arg(kernel_merge, 2, 0)
811 call accel_set_kernel_arg(kernel_merge, 3, im_out)
812 call accel_set_kernel_arg(kernel_merge, 4, 0)
813 call accel_set_kernel_arg(kernel_merge, 5, pot_buffer)
814 call accel_set_kernel_arg(kernel_merge, 6, 0)
815 call accel_grid_size_extend_dim(int(np_tot, int64), 1_int64, gsizes, bsizes, kernel_merge)
816 call accel_kernel_run(kernel_merge, gsizes, bsizes)
817 call accel_finish()
818
819 call accel_free_buffer(re_in)
820 call accel_free_buffer(im_in)
821 call accel_free_buffer(re_out)
822 call accel_free_buffer(im_out)
823
824 call profiling_out('POISSON_RE_IM_ACCEL')
827
828 !-----------------------------------------------------------------
829
830 subroutine zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
831 type(poisson_t), intent(in) :: this
832 type(namespace_t), intent(in) :: namespace
833 complex(real64), contiguous, intent(inout) :: pot(:)
834 complex(real64), contiguous, intent(in) :: rho(:)
835 logical, optional, intent(in) :: all_nodes
836 type(fourier_space_op_t), optional, intent(in) :: kernel
837 logical, optional, intent(in) :: reset
838
839 logical :: all_nodes_value
840
842
843 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
844
845 assert(ubound(pot, dim = 1) == this%der%mesh%np_part .or. ubound(pot, dim = 1) == this%der%mesh%np)
846 assert(ubound(rho, dim = 1) == this%der%mesh%np_part .or. ubound(rho, dim = 1) == this%der%mesh%np)
847
848 assert(this%method /= poisson_null)
849
850 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
851 pot(1:this%der%mesh%np) = m_zero
852 end if
853
854 if (this%method == poisson_fft .and. this%kernel /= poisson_fft_kernel_corrected &
855 .and. .not. this%is_dressed) then
856 !The default (real) Poisson solver is used for OEP and Sternheimer calls were we do not need
857 !a complex-to-xomplex FFT as these parts use the normal Coulomb potential
858 if (this%cube%fft%type == fft_complex) then
859 !We add the profiling here, as the other path uses dpoisson_solve
860 call profiling_in('ZPOISSON_SOLVE')
861 call zpoisson_fft_solve(this%fft_solver, this%der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
862 call profiling_out('ZPOISSON_SOLVE')
863 else
864 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel=kernel)
865 end if
866 else
867 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel = kernel)
868 end if
869
870 pop_sub(zpoisson_solve)
871 end subroutine zpoisson_solve
872
873
874 !-----------------------------------------------------------------
875
876 subroutine poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
877 type(poisson_t), intent(inout) :: this
878 type(namespace_t), intent(in) :: namespace
879 type(batch_t), intent(inout) :: potb
880 type(batch_t), intent(inout) :: rhob
881 logical, optional, intent(in) :: all_nodes
882 type(fourier_space_op_t), optional, intent(in) :: kernel
883
884 integer :: ii
885
886 push_sub(poisson_solve_batch)
887
888 assert(potb%nst_linear == rhob%nst_linear)
889 assert(potb%type() == rhob%type())
890
891 if (potb%type() == type_float) then
892 do ii = 1, potb%nst_linear
893 call dpoisson_solve(this, namespace, potb%dff_linear(:, ii), rhob%dff_linear(:, ii), all_nodes, kernel=kernel)
894 end do
895 else
896 do ii = 1, potb%nst_linear
897 call zpoisson_solve(this, namespace, potb%zff_linear(:, ii), rhob%zff_linear(:, ii), all_nodes, kernel=kernel)
898 end do
899 end if
900
901 pop_sub(poisson_solve_batch)
902 end subroutine poisson_solve_batch
903
904 !-----------------------------------------------------------------
910 logical function poisson_is_batch_capable(this)
911 type(poisson_t), intent(in) :: this
912
913 poisson_is_batch_capable = this%method == poisson_fft &
914 .and. this%kernel /= poisson_fft_kernel_corrected
915 end function poisson_is_batch_capable
916
917 !-----------------------------------------------------------------
919 logical function poisson_is_device_batch_capable(this)
920 type(poisson_t), intent(in) :: this
921
922 ! Tested in steps: only a batch-capable solver is guaranteed to have an FFT cube.
924 if (.not. accel_is_enabled()) return
925 if (.not. poisson_is_batch_capable(this)) return
926 poisson_is_device_batch_capable = this%cube%fft%library == fftlib_accel &
927 .and. .not. this%cube%parallel_in_domains
929
930 !-----------------------------------------------------------------
931
937 subroutine dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
938 type(poisson_t), intent(in) :: this
939 type(namespace_t), intent(in) :: namespace
940 real(real64), contiguous, intent(inout) :: pot(:)
941 real(real64), contiguous, intent(in) :: rho(:)
945 logical, optional, intent(in) :: all_nodes
946 type(fourier_space_op_t), optional, intent(in) :: kernel
947 logical, optional, intent(in) :: reset
948
949 type(derivatives_t), pointer :: der
950 real(real64), allocatable :: rho_corrected(:), vh_correction(:)
951 logical :: all_nodes_value
952
953 call profiling_in('POISSON_SOLVE')
954 push_sub(dpoisson_solve)
955
956 der => this%der
957
958 assert(ubound(pot, dim = 1) == der%mesh%np_part .or. ubound(pot, dim = 1) == der%mesh%np)
959 assert(ubound(rho, dim = 1) == der%mesh%np_part .or. ubound(rho, dim = 1) == der%mesh%np)
960
961 ! Check optional argument and set to default if necessary.
962 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
963
964 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
965 pot(1:der%mesh%np) = m_zero
966 end if
967
968 assert(this%method /= poisson_null)
969
970 if (present(kernel)) then
971 assert(this%method == poisson_fft)
972 end if
973
974 select case (this%method)
975 case (poisson_direct_sum)
976 if ((this%is_dressed .and. this%der%dim - 1 > 3) .or. this%der%dim > 3) then
977 message(1) = "Direct sum Poisson solver only available for 1, 2, or 3 dimensions."
978 call messages_fatal(1, namespace=namespace)
979 end if
980 call poisson_solve_direct(this, namespace, pot, rho)
981
982 case (poisson_cg)
983 call poisson_cg1(namespace, der, this%corrector, pot, rho)
984
986 safe_allocate(rho_corrected(1:der%mesh%np))
987 safe_allocate(vh_correction(1:der%mesh%np_part))
988
989 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
991 call lalg_axpy(der%mesh%np, -m_one, vh_correction, pot)
992 call poisson_cg2(namespace, der, pot, rho_corrected)
993 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
994
995 safe_deallocate_a(rho_corrected)
996 safe_deallocate_a(vh_correction)
997
998 case (poisson_multigrid)
999 call poisson_multigrid_solver(this%mg, namespace, der, pot, rho)
1000
1001 case (poisson_fft)
1002 if (this%kernel /= poisson_fft_kernel_corrected) then
1003 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
1004 else
1005 safe_allocate(rho_corrected(1:der%mesh%np))
1006 safe_allocate(vh_correction(1:der%mesh%np_part))
1007
1008 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
1009 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho_corrected, this%mesh_cube_map, &
1010 average_to_zero = .true., kernel=kernel)
1011
1012 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
1013 safe_deallocate_a(rho_corrected)
1014 safe_deallocate_a(vh_correction)
1015 end if
1016
1018 call poisson_isf_solve(this%isf_solver, der%mesh, this%cube, pot, rho, all_nodes_value)
1019
1020
1021 case (poisson_psolver)
1022 if (this%psolver_solver%datacode == "G") then
1023 ! Global version
1024 call poisson_psolver_global_solve(this%psolver_solver, der%mesh, this%cube, pot, rho)
1025 else ! "D" Distributed version
1026 call poisson_psolver_parallel_solve(this%psolver_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map)
1027 end if
1028
1029 case (poisson_no)
1030 call poisson_no_solve(this%no_solver, der%mesh, pot, rho)
1031 end select
1032
1033 ! Add extra terms for dressed interaction
1034 if (this%is_dressed .and. this%method /= poisson_no) then
1035 call photon_mode_add_poisson_terms(this%photons, der%mesh, rho, pot)
1036 end if
1037
1038 pop_sub(dpoisson_solve)
1039 call profiling_out('POISSON_SOLVE')
1040 end subroutine dpoisson_solve
1041
1042 !-----------------------------------------------------------------
1043 subroutine poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
1044 type(poisson_t), intent(inout) :: this
1045 type(namespace_t), intent(in) :: namespace
1046 class(space_t), intent(in) :: space
1047 type(poisson_t), intent(in) :: main
1048 type(derivatives_t), target, intent(in) :: der
1049 type(submesh_t), intent(inout) :: sm
1050 type(mpi_grp_t), intent(in) :: grp
1051 integer, optional, intent(in) :: method
1052 logical, optional, intent(in) :: force_cmplx
1053
1054 integer :: default_solver, idir, iter, maxl
1055 integer :: box(space%dim)
1056 real(real64) :: qq(der%dim), threshold
1057
1058 if (this%method /= poisson_null) return ! already initialized
1059
1060 push_sub(poisson_init_sm)
1061
1062 this%is_dressed = .false.
1063 !TODO: To be implemented as an option
1064 this%all_nodes_default = .false.
1065
1066 this%nslaves = 0
1067 this%der => der
1068
1069#ifdef HAVE_MPI
1070 this%all_nodes_default = main%all_nodes_default
1071#endif
1072
1073 default_solver = poisson_direct_sum
1074 this%method = default_solver
1075 if (present(method)) this%method = method
1076
1077 if (der%mesh%use_curvilinear) then
1078 call messages_not_implemented("Submesh Poisson solver with curvilinear mesh", namespace=namespace)
1079 end if
1080
1081 this%kernel = poisson_fft_kernel_none
1082
1083 select case (this%method)
1084 case (poisson_direct_sum)
1085 !Nothing to be done
1086
1087 case (poisson_isf)
1088 !TODO: Add support for domain parrallelization
1089 assert(.not. der%mesh%parallel_in_domains)
1090 call submesh_get_cube_dim(sm, space, box)
1091 call submesh_init_cube_map(sm, space)
1092 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1093 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1094 call cube_init_cube_map(this%cube, sm%mesh)
1095 call poisson_isf_init(this%isf_solver, namespace, der%mesh, this%cube, grp%comm, init_world = this%all_nodes_default)
1096
1097 case (poisson_psolver)
1098 !TODO: Add support for domain parrallelization
1099 assert(.not. der%mesh%parallel_in_domains)
1100 if (this%all_nodes_default) then
1101 this%cube%mpi_grp = grp
1102 else
1103 this%cube%mpi_grp = this%der%mesh%mpi_grp
1104 end if
1105 call submesh_get_cube_dim(sm, space, box)
1106 call submesh_init_cube_map(sm, space)
1107 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1108 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1109 call cube_init_cube_map(this%cube, sm%mesh)
1110 qq = m_zero
1111 call poisson_psolver_init(this%psolver_solver, namespace, space, this%cube, m_zero, qq, force_isolated=.true.)
1112 call poisson_psolver_get_dims(this%psolver_solver, this%cube)
1113 case (poisson_fft)
1114 !Here we impose zero boundary conditions
1115 this%kernel = poisson_fft_kernel_sph
1116
1117 call submesh_get_cube_dim(sm, space, box)
1118 call submesh_init_cube_map(sm, space)
1119 !We double the size of the cell
1120 !Maybe the factor of two should be controlled as a variable
1121 do idir = 1, space%dim
1122 box(idir) = (2 * (box(idir) - 1)) + 1
1123 end do
1124 if (optional_default(force_cmplx, .false.)) then
1125 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1126 fft_type = fft_complex, need_partition=.not.der%mesh%parallel_in_domains)
1127 else
1128 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1129 fft_type = fft_real, need_partition=.not.der%mesh%parallel_in_domains)
1130 end if
1131 call poisson_fft_init(this%fft_solver, namespace, space, this%cube, this%kernel)
1132 case (poisson_cg)
1133 call parse_variable(namespace, 'PoissonSolverMaxMultipole', 4, maxl)
1134 write(message(1),'(a,i2)')'Info: Boundary conditions fixed up to L =', maxl
1135 call messages_info(1, namespace=namespace)
1136 call parse_variable(namespace, 'PoissonSolverMaxIter', 500, iter)
1137 call parse_variable(namespace, 'PoissonSolverThreshold', 1.0e-6_real64, threshold)
1138 call poisson_corrections_init(this%corrector, namespace, space, maxl, this%der%mesh)
1139 call poisson_cg_init(threshold, iter)
1140 end select
1141
1142 pop_sub(poisson_init_sm)
1143 end subroutine poisson_init_sm
1144
1145 ! -----------------------------------------------------------------
1146
1147 logical pure function poisson_solver_is_iterative(this) result(iterative)
1148 type(poisson_t), intent(in) :: this
1149
1150 iterative = this%method == poisson_cg .or. this%method == poisson_cg_corrected
1151 end function poisson_solver_is_iterative
1152
1153 !-----------------------------------------------------------------
1154 subroutine poisson_async_init(this, mc)
1155 type(poisson_t), intent(inout) :: this
1156 type(multicomm_t), intent(in) :: mc
1157
1158 push_sub(poisson_async_init)
1159
1160#ifdef HAVE_MPI
1161 if (multicomm_have_slaves(mc)) then
1162
1163 call mpi_grp_init(this%local_grp, mc%group_comm(p_strategy_states))
1164
1165 this%root = (this%local_grp%is_root())
1166
1167 this%intercomm = mc%slave_intercomm
1168 call mpi_comm_remote_size(this%intercomm, this%nslaves)
1169
1170 end if
1171#endif
1172
1173 pop_sub(poisson_async_init)
1174
1175 end subroutine poisson_async_init
1176
1177 !-----------------------------------------------------------------
1178
1179 subroutine poisson_async_end(this, mc)
1180 type(poisson_t), intent(inout) :: this
1181 type(multicomm_t), intent(in) :: mc
1182
1183#ifdef HAVE_MPI
1184 integer :: islave
1185#endif
1186
1187 push_sub(poisson_async_end)
1188
1189#ifdef HAVE_MPI
1190 if (multicomm_have_slaves(mc)) then
1191
1192 ! send the finish signal
1193 do islave = this%local_grp%rank, this%nslaves - 1, this%local_grp%size
1194 call mpi_send(m_one, 1, mpi_double_precision, islave, cmd_finish, this%intercomm)
1195 end do
1196
1197 end if
1198#endif
1199
1200 pop_sub(poisson_async_end)
1201
1202 end subroutine poisson_async_end
1203
1204 !-----------------------------------------------------------------
1205
1206 subroutine poisson_slave_work(this, namespace)
1207 type(poisson_t), intent(inout) :: this
1208 type(namespace_t), intent(in) :: namespace
1209
1210#ifdef HAVE_MPI
1211 real(real64), allocatable :: rho(:), pot(:)
1212 logical :: done
1213 type(mpi_status) :: status
1214 integer :: bcast_root
1215
1216 push_sub(poisson_slave_work)
1217 call profiling_in("SLAVE_WORK")
1218
1219 safe_allocate(rho(1:this%der%mesh%np))
1220 safe_allocate(pot(1:this%der%mesh%np))
1221 done = .false.
1222
1223 do while(.not. done)
1224
1225 call profiling_in("SLAVE_WAIT")
1226 call mpi_recv(rho(1), this%der%mesh%np, mpi_double_precision, mpi_any_source, mpi_any_tag, this%intercomm, status)
1227 call profiling_out("SLAVE_WAIT")
1228
1229 ! The tag of the message tells us what we have to do.
1230 select case (status%MPI_TAG)
1231
1232 case (cmd_finish)
1233 done = .true.
1235 case (cmd_poisson_solve)
1236 call dpoisson_solve(this, namespace, pot, rho)
1237
1238 call profiling_in("SLAVE_BROADCAST")
1239 bcast_root = mpi_proc_null
1240 if (this%root) bcast_root = mpi_root
1241 call mpi_bcast(pot(1), this%der%mesh%np, mpi_double_precision, bcast_root, this%intercomm)
1242 call profiling_out("SLAVE_BROADCAST")
1243
1244 end select
1245
1246 end do
1247
1248 safe_deallocate_a(pot)
1249 safe_deallocate_a(rho)
1250
1251 call profiling_out("SLAVE_WORK")
1252 pop_sub(poisson_slave_work)
1253#endif
1254 end subroutine poisson_slave_work
1255
1256 !----------------------------------------------------------------
1257
1258 logical pure function poisson_is_async(this) result(async)
1259 type(poisson_t), intent(in) :: this
1260
1261 async = (this%nslaves > 0)
1263 end function poisson_is_async
1264
1265 !----------------------------------------------------------------
1266
1267 subroutine poisson_build_kernel(this, namespace, space, coulb, qq, cam, singul)
1268 type(poisson_t), intent(in) :: this
1269 type(namespace_t), intent(in) :: namespace
1270 class(space_t), intent(in) :: space
1271 type(fourier_space_op_t), intent(inout) :: coulb
1272 real(real64), intent(in) :: qq(:)
1273 type(xc_cam_t), intent(in) :: cam
1274 real(real64), optional, intent(in) :: singul
1275
1276 logical :: reinit
1277
1278 push_sub(poisson_build_kernel)
1280 if (space%is_periodic()) then
1281 assert(ubound(qq, 1) >= space%periodic_dim)
1282 assert(this%method == poisson_fft)
1283 end if
1284
1285 if (cam%omega > m_epsilon) then
1286 if (this%method /= poisson_fft) then
1287 write(message(1),'(a)') "Poisson solver with range separation is only implemented with FFT."
1288 call messages_fatal(1, namespace=namespace)
1289 end if
1290 end if
1291
1292 !We only reinitialize the poisson solver if needed
1293 reinit = .false.
1294 if (allocated(coulb%qq)) then
1295 reinit = any(abs(coulb%qq(1:space%periodic_dim) - qq(1:space%periodic_dim)) > m_epsilon)
1296 end if
1297 reinit = reinit .or. (abs(coulb%mu - cam%omega) > m_epsilon .and. cam%omega > m_epsilon)
1298 reinit = reinit .or. (abs(coulb%alpha - cam%alpha) > m_epsilon .and. cam%alpha > m_epsilon)
1299 reinit = reinit .or. (abs(coulb%beta - cam%beta) > m_epsilon .and. cam%beta > m_epsilon)
1300
1301 if (reinit) then
1302 call profiling_in('POISSON_BUILD_KERNEL')
1303 !TODO: this should be a select case supporting other kernels.
1304 ! This means that we need an abstract object for kernels.
1305 select case (this%method)
1306 case (poisson_fft)
1307 ! Check that we are consistent: the Poisson solver supports must return 1 here
1308 assert(is_close(poisson_get_full_range_weight(this, cam), m_one))
1309 call coulb%end()
1310 call coulb%init(space, qq, cam, singul)
1311 call poisson_fft_get_kernel(namespace, space, this%cube, coulb, this%kernel, &
1312 this%poisson_soft_coulomb_param)
1313 case default
1314 call messages_not_implemented("poisson_build_kernel with other methods than FFT", namespace=namespace)
1315 end select
1316 call profiling_out('POISSON_BUILD_KERNEL')
1317 end if
1318
1319 pop_sub(poisson_build_kernel)
1320 end subroutine poisson_build_kernel
1321
1322 !----------------------------------------------------------------
1331 real(real64) function poisson_get_full_range_weight(this, cam) result(weight)
1332 type(poisson_t), intent(in) :: this
1333 type(xc_cam_t), intent(in) :: cam
1334
1335 select case (this%method)
1336 case (poisson_fft)
1337 weight = m_one
1338 case default
1339 if(cam%omega < m_epsilon) then
1340 weight = cam%alpha
1341 else if(cam%alpha > m_epsilon .and. cam%beta < m_epsilon) then
1342 weight = cam%alpha
1343 else if(cam%alpha < m_epsilon .and. cam%beta > m_epsilon) then
1344 weight = cam%beta
1345 else
1346 assert(.false.)
1347 end if
1348 end select
1350
1351#include "poisson_init_inc.F90"
1352#include "poisson_direct_inc.F90"
1353#include "poisson_direct_sm_inc.F90"
1354
1355#include "undef.F90"
1356#include "real.F90"
1357#include "poisson_inc.F90"
1358#include "undef.F90"
1359#include "complex.F90"
1360#include "poisson_inc.F90"
1361
1362end module poisson_oct_m
1363
1364!! Local Variables:
1365!! mode: f90
1366!! coding: utf-8
1367!! End:
constant times a vector plus a vector
Definition: lalg_basic.F90:173
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:182
subroutine, public accel_free_buffer(this, async)
Definition: accel.F90:945
subroutine, public accel_kernel_start_call(this, file_name, kernel_name, flags)
Definition: accel.F90:1743
subroutine, public accel_finish()
Definition: accel.F90:1082
integer, parameter, public accel_mem_read_write
Definition: accel.F90:185
pure logical function, public accel_is_enabled()
Definition: accel.F90:376
This module implements batches of mesh functions.
Definition: batch.F90:135
This module handles the calculation mode.
integer, parameter, public p_strategy_kpoints
parallelization in k-points
subroutine, public cube_end(cube)
Definition: cube.F90:402
subroutine, public cube_init(cube, nn, namespace, space, spacing, coord_system, fft_type, fft_library, dont_optimize, nn_out, mpi_grp, need_partition, tp_enlarge, blocksize, batch_size, nthreads)
Definition: cube.F90:208
subroutine, public cube_init_cube_map(cube, mesh)
Definition: cube.F90:885
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:120
integer, parameter, public fft_none
global constants
Definition: fft.F90:174
integer, public fft_default_lib
Definition: fft.F90:257
integer, parameter, public fftlib_accel
Definition: fft.F90:179
integer, parameter, public fft_real
Definition: fft.F90:174
integer, parameter, public fft_complex
Definition: fft.F90:174
integer, parameter, public fftlib_pfft
Definition: fft.F90:179
integer, parameter, public fftlib_fftw
Definition: fft.F90:179
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public m_one
Definition: global.F90:201
real(real64), parameter, public m_three
Definition: global.F90:203
This module implements the index, used for the mesh points.
Definition: index.F90:124
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public mesh_cube_parallel_map_end(this)
subroutine, public mesh_cube_parallel_map_init(this, mesh, cube)
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public mesh_double_box(space, mesh, alpha, db)
finds the dimension of a box doubled in the non-periodic dimensions
Definition: mesh.F90:286
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1068
character(len=512), private msg
Definition: messages.F90:167
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_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
logical pure function, public multicomm_strategy_is_parallel(mc, level)
Definition: multicomm.F90:728
logical pure function, public multicomm_have_slaves(this)
Definition: multicomm.F90:854
Some general things and nomenclature:
Definition: par_vec.F90:173
subroutine, public photon_mode_compute_dipoles(this, mesh)
Computes the polarization dipole.
subroutine, public photon_mode_add_poisson_terms(this, mesh, rho, pot)
subroutine, public photon_mode_end(this)
subroutine, public photon_mode_set_n_electrons(this, qtot)
subroutine, public photon_mode_init(this, namespace, dim, photon_free)
real(real64), public threshold
Definition: poisson_cg.F90:141
subroutine, public poisson_cg2(namespace, der, pot, rho)
Definition: poisson_cg.F90:231
subroutine, public poisson_cg1(namespace, der, corrector, pot, rho)
Definition: poisson_cg.F90:167
subroutine, public poisson_cg_init(thr, itr)
Definition: poisson_cg.F90:149
subroutine, public poisson_cg_end
Definition: poisson_cg.F90:161
subroutine, public poisson_corrections_end(this)
subroutine, public poisson_corrections_init(this, namespace, space, ml, mesh)
subroutine, public correct_rho(this, der, rho, rho_corrected, vh_correction)
integer, parameter, public poisson_fft_kernel_nocut
integer, parameter, public poisson_fft_kernel_cyl
subroutine, public zpoisson_fft_solve(this, mesh, cube, pot, rho, mesh_cube_map, average_to_zero, kernel, sm)
subroutine, public poisson_fft_end(this)
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_none
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, public poisson_isf_end(this)
subroutine, public poisson_isf_init(this, namespace, mesh, cube, all_nodes_comm, init_world)
subroutine, public poisson_isf_solve(this, mesh, cube, pot, rho, all_nodes, sm)
subroutine, public poisson_multigrid_solver(this, namespace, der, pot, rho)
A multigrid Poisson solver with corrections at the boundaries.
subroutine, public poisson_multigrid_end(this)
subroutine, public poisson_no_solve(this, mesh, pot, rho)
Definition: poisson_no.F90:164
subroutine, public poisson_no_end(this)
Definition: poisson_no.F90:152
subroutine, public zpoisson_solve_sm(this, namespace, sm, pot, rho, all_nodes)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:2425
integer, parameter, public poisson_multigrid
Definition: poisson.F90:191
subroutine poisson_kernel_init(this, namespace, space, mc, stencil)
Definition: poisson.F90:1384
integer, parameter, public poisson_psolver
Definition: poisson.F90:191
subroutine, public dpoisson_solve_start(this, rho)
Definition: poisson.F90:2149
integer, parameter cmd_finish
Definition: poisson.F90:227
subroutine, public zpoisson_solve_finish(this, pot)
Definition: poisson.F90:2413
subroutine poisson_solve_direct(this, namespace, pot, rho)
Definition: poisson.F90:1595
integer, parameter, public poisson_fft
Definition: poisson.F90:191
subroutine, public zpoisson_solve_batch(this, namespace, pot, rho, kernel, all_nodes, pot_buffer, rho_buffer, count)
Solves the Poisson equation for batched quantities, using fast Fourier transforms (FFTs).
Definition: poisson.F90:2560
subroutine, public zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Definition: poisson.F90:911
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
Definition: poisson.F90:1124
subroutine, public poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
Definition: poisson.F90:957
subroutine, public poisson_async_init(this, mc)
Definition: poisson.F90:1235
subroutine, public dpoisson_solve_sm(this, namespace, sm, pot, rho, all_nodes)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:2169
subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
Definition: poisson.F90:744
logical pure function poisson_solver_is_iterative(this)
Definition: poisson.F90:1228
subroutine, public poisson_slave_work(this, namespace)
Definition: poisson.F90:1263
subroutine zpoisson_solve_real_and_imag_separately_accel(this, namespace, pot_buffer, rho_buffer, kernel, count)
Device variant of zpoisson_solve_real_and_imag_separately.
Definition: poisson.F90:842
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:1018
integer, parameter cmd_poisson_solve
Definition: poisson.F90:227
integer, parameter, public poisson_cg
Definition: poisson.F90:191
subroutine, public poisson_build_kernel(this, namespace, space, coulb, qq, cam, singul)
Definition: poisson.F90:1280
subroutine, public dpoisson_solve_finish(this, pot)
Definition: poisson.F90:2157
subroutine, public poisson_init(this, namespace, space, der, mc, stencil, qtot, label, solver, verbose, force_serial, force_cmplx, fft_batch_size)
Definition: poisson.F90:236
subroutine, public zpoisson_solve_start(this, rho)
Definition: poisson.F90:2405
subroutine zpoisson_solve_real_and_imag_separately_batch(this, namespace, pot, rho, kernel)
Batched analogue of zpoisson_solve_real_and_imag_separately.
Definition: poisson.F90:803
subroutine, public poisson_async_end(this, mc)
Definition: poisson.F90:1247
integer, parameter, public poisson_cg_corrected
Definition: poisson.F90:191
logical function, public poisson_is_device_batch_capable(this)
Whether a batch can be solved with the densities and potentials kept on the device.
Definition: poisson.F90:1000
integer, parameter, public poisson_isf
Definition: poisson.F90:191
real(real64) function, public poisson_get_full_range_weight(this, cam)
Most Poisson solvers do not implement Coulomb attenuated potentials, and can only be used for global ...
Definition: poisson.F90:1344
subroutine, public dpoisson_solve_batch(this, namespace, pot, rho, kernel, all_nodes, pot_buffer, rho_buffer, count)
Solves the Poisson equation for batched quantities, using fast Fourier transforms (FFTs).
Definition: poisson.F90:2248
integer, parameter, public poisson_null
Definition: poisson.F90:191
integer, parameter, public poisson_no
Definition: poisson.F90:191
logical pure function, public poisson_is_async(this)
Definition: poisson.F90:1271
subroutine, public poisson_end(this)
Definition: poisson.F90:691
logical function poisson_is_batch_capable(this)
Whether this solver can transform a whole batch of functions in one call.
Definition: poisson.F90:991
subroutine, public poisson_psolver_global_solve(this, mesh, cube, pot, rho, sm)
subroutine, public poisson_psolver_parallel_solve(this, mesh, cube, pot, rho, mesh_cube_map)
subroutine, public poisson_psolver_end(this)
subroutine, public poisson_psolver_get_dims(this, cube)
subroutine, public poisson_psolver_init(this, namespace, space, cube, mu, qq, force_isolated)
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:631
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:554
This module defines stencils used in Octopus.
Definition: stencil.F90:137
subroutine, public submesh_init_cube_map(sm, space)
Definition: submesh.F90:935
subroutine, public submesh_get_cube_dim(sm, space, db)
finds the dimension of a box containing the submesh
Definition: submesh.F90:900
type(type_t), parameter, public type_float
Definition: types.F90:135
This module defines the unit system, used for input and output.
Class defining batches of mesh functions.
Definition: batch.F90:162
Class implementing a box that is a union of spheres. We do this in a specific class instead of using ...
class representing derivatives
Definition of a Fourier Space Coulomb Kernel.
This is defined even when running serial.
Definition: mpi.F90:144
A submesh is a type of mesh, used for the projectors in the pseudopotentials It contains points on a ...
Definition: submesh.F90:174
int true(void)