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
401 select case (space%dim)
402 case (1)
403
404 select case (space%periodic_dim)
405 case (0)
406 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
407 message(1) = 'A finite 1D system may only use fft or direct_sum Poisson solvers.'
408 call messages_fatal(1, namespace=namespace)
409 end if
410 case (1)
411 if (this%method /= poisson_fft) then
412 message(1) = 'A periodic 1D system may only use the fft Poisson solver.'
413 call messages_fatal(1, namespace=namespace)
414 end if
415 end select
416
417 if (der%mesh%use_curvilinear .and. this%method /= poisson_direct_sum) then
418 message(1) = 'If curvilinear coordinates are used in 1D, then the only working'
419 message(2) = 'Poisson solver is direct_sum.'
420 call messages_fatal(2, namespace=namespace)
421 end if
422
423 case (2)
424
425 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
426 message(1) = 'A 2D system may only use fft or direct_sum solvers.'
427 call messages_fatal(1, namespace=namespace)
428 end if
429
430 if (der%mesh%use_curvilinear .and. (this%method /= poisson_direct_sum)) then
431 message(1) = 'If curvilinear coordinates are used in 2D, then the only working'
432 message(2) = 'Poisson solver is direct_sum.'
433 call messages_fatal(2, namespace=namespace)
434 end if
435
436 case (3)
437
438 if (space%is_periodic() .and. this%method == poisson_isf) then
439 call messages_write('The ISF solver can only be used for finite systems.')
440 call messages_fatal()
441 end if
442
443 if (space%is_periodic() .and. this%method == poisson_fft .and. &
444 this%kernel /= space%periodic_dim .and. this%kernel >= 0 .and. this%kernel <= 3) then
445 write(message(1), '(a,i1,a)')'The system is periodic in ', space%periodic_dim ,' dimension(s),'
446 write(message(2), '(a,i1,a)')'but Poisson solver is set for ', this%kernel, ' dimensions.'
447 call messages_warning(2, namespace=namespace)
448 end if
449
450 if (space%is_periodic() .and. this%method == poisson_fft .and. this%kernel == poisson_fft_kernel_corrected) then
451 write(message(1), '(a,i1,a)')'PoissonFFTKernel = multipole_correction cannot be used for periodic systems.'
452 call messages_fatal(1, namespace=namespace)
453 end if
454
455 if (der%mesh%use_curvilinear .and. .not. any(this%method == [poisson_cg_corrected, poisson_multigrid])) then
456 message(1) = 'If curvilinear coordinates are used, then the only working'
457 message(2) = 'Poisson solvers are cg_corrected and multigrid.'
458 call messages_fatal(2, namespace=namespace)
459 end if
460 if (der%mesh%use_curvilinear .and. this%method == poisson_multigrid .and. accel_is_enabled()) then
461 call messages_not_implemented('Multigrid Poisson solver with curvilinear coordinates on GPUs')
462 end if
463
464 select type (box => der%mesh%box)
465 type is (box_minimum_t)
466 if (this%method == poisson_cg_corrected) then
467 message(1) = 'When using the "minimum" box shape and the "cg_corrected"'
468 message(2) = 'Poisson solver, we have observed "sometimes" some non-'
469 message(3) = 'negligible error. You may want to check that the "fft" or "cg"'
470 message(4) = 'solver are providing, in your case, the same results.'
471 call messages_warning(4, namespace=namespace)
472 end if
473 end select
474
475 end select
476 end if
477
478 if (this%method == poisson_psolver) then
479#if !(defined HAVE_PSOLVER)
480 message(1) = "The PSolver Poisson solver cannot be used since the code was not compiled with the PSolver library."
481 call messages_fatal(1, namespace=namespace)
482#endif
483 end if
484
485 if (optional_default(verbose,.true.)) then
486 call messages_print_with_emphasis(namespace=namespace)
487 end if
488
489 ! Now that we know the method, we check if we need a cube and its dimensions
490 need_cube = .false.
491 fft_type = fft_real
492 if (optional_default(force_cmplx, .false.)) fft_type = fft_complex
493
494 if (this%method == poisson_isf .or. this%method == poisson_psolver) then
495 fft_type = fft_none
496 box(:) = der%mesh%idx%ll(:)
497 need_cube = .true.
498 end if
499
500 if (this%method == poisson_psolver .and. multicomm_have_slaves(mc)) then
501 call messages_not_implemented('Task parallelization with PSolver Poisson solver', namespace=namespace)
502 end if
503
505 ! Documentation in poisson_psolver.F90
506 call parse_variable(namespace, 'PoissonSolverPSolverParallelData', .true., isf_data_is_parallel)
507 if (this%method == poisson_psolver .and. isf_data_is_parallel) then
508 call messages_not_implemented("k-point parallelization with PSolver library and", namespace=namespace)
509 call messages_not_implemented("PoissonSolverPSolverParallelData = yes", namespace=namespace)
510 end if
511 if (this%method == poisson_fft .and. fft_library == fftlib_pfft) then
512 call messages_not_implemented("k-point parallelization with PFFT library for", namespace=namespace)
513 call messages_not_implemented("PFFT library for Poisson solver", namespace=namespace)
514 end if
515 end if
516
517 if (this%method == poisson_fft) then
518
519 need_cube = .true.
520
521 !%Variable DoubleFFTParameter
522 !%Type float
523 !%Default 2.0
524 !%Section Mesh::FFTs
525 !%Description
526 !% For solving the Poisson equation in Fourier space, and for applying the local potential
527 !% in Fourier space, an auxiliary cubic mesh is built. This mesh will be larger than
528 !% the circumscribed cube of the usual mesh by a factor <tt>DoubleFFTParameter</tt>. See
529 !% the section that refers to Poisson equation, and to the local potential for details
530 !% [the default value of two is typically good].
531 !%End
532 call parse_variable(namespace, 'DoubleFFTParameter', m_two, fft_alpha)
533 if (fft_alpha < m_one .or. fft_alpha > m_three) then
534 write(message(1), '(a,f12.5,a)') "Input: '", fft_alpha, &
535 "' is not a valid DoubleFFTParameter"
536 message(2) = '1.0 <= DoubleFFTParameter <= 3.0'
537 call messages_fatal(2, namespace=namespace)
538 end if
539
540 if (space%dim /= 3 .and. fft_library == fftlib_pfft) then
541 call messages_not_implemented('PFFT support for dimensionality other than 3', namespace=namespace)
542 end if
543
544 select case (space%dim)
545
546 case (1)
547 select case (this%kernel)
549 call mesh_double_box(space, der%mesh, fft_alpha, box)
551 box = der%mesh%idx%ll
552 end select
553
554 case (2)
555 select case (this%kernel)
557 call mesh_double_box(space, der%mesh, fft_alpha, box)
558 box(1:2) = maxval(box)
560 call mesh_double_box(space, der%mesh, fft_alpha, box)
562 box(:) = der%mesh%idx%ll(:)
563 end select
564
565 case (3)
566 select case (this%kernel)
568 call mesh_double_box(space, der%mesh, fft_alpha, box)
569 box(:) = maxval(box)
571 call mesh_double_box(space, der%mesh, fft_alpha, box)
572 box(2) = maxval(box(2:3)) ! max of finite directions
573 box(3) = maxval(box(2:3)) ! max of finite directions
575 box(:) = der%mesh%idx%ll(:)
577 call mesh_double_box(space, der%mesh, fft_alpha, box)
578 end select
579
580 end select
581
582 end if
583
584 ! Solvers that cannot transform a whole batch at once are applied one function at a time
585 ! (see X(poisson_solve_batch)) and do not need a batched cube.
586 if (.not. poisson_is_batch_capable(this)) fft_bs = 1
587
588 ! Create the cube
589 if (need_cube) then
590 call cube_init(this%cube, box, namespace, space, der%mesh%spacing, &
591 der%mesh%coord_system, fft_type = fft_type, &
592 need_partition=.not.der%mesh%parallel_in_domains, &
593 batch_size=fft_bs)
594 call cube_init_cube_map(this%cube, der%mesh)
595 if (this%cube%parallel_in_domains .and. this%method == poisson_fft) then
596 call mesh_cube_parallel_map_init(this%mesh_cube_map, der%mesh, this%cube)
597 end if
598 end if
599
600 if (this%is_dressed .and. .not. this%method == poisson_direct_sum) then
601 write(message(1), '(a)')'Dressed Orbital calculation currently only working with direct sum Poisson solver.'
602 call messages_fatal(1, namespace=namespace)
603 end if
604
605 call poisson_kernel_init(this, namespace, space, mc, stencil)
606
607 pop_sub(poisson_init)
608 end subroutine poisson_init
609
610 !-----------------------------------------------------------------
611 subroutine poisson_end(this)
612 type(poisson_t), intent(inout) :: this
613
614 logical :: has_cube
615
616 push_sub(poisson_end)
617
618 has_cube = .false.
619
620 select case (this%method)
621 case (poisson_fft)
622 call poisson_fft_end(this%fft_solver)
623 if (this%kernel == poisson_fft_kernel_corrected) call poisson_corrections_end(this%corrector)
624 has_cube = .true.
625
627 call poisson_cg_end()
628 call poisson_corrections_end(this%corrector)
629
630 case (poisson_multigrid)
631 call poisson_multigrid_end(this%mg)
632
633 case (poisson_isf)
634 call poisson_isf_end(this%isf_solver)
635 has_cube = .true.
636
637 case (poisson_psolver)
638 call poisson_psolver_end(this%psolver_solver)
639 has_cube = .true.
640
641 case (poisson_no)
642 call poisson_no_end(this%no_solver)
643
644 end select
645 this%method = poisson_null
646
647 if (has_cube) then
648 if (this%cube%parallel_in_domains) then
649 call mesh_cube_parallel_map_end(this%mesh_cube_map)
650 end if
651 call cube_end(this%cube)
652 end if
653
654 if (this%is_dressed) then
655 call photon_mode_end(this%photons)
656 end if
657 this%is_dressed = .false.
658
659 pop_sub(poisson_end)
660 end subroutine poisson_end
661
662 !-----------------------------------------------------------------
663
664 subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
665 type(poisson_t), intent(in) :: this
666 type(namespace_t), intent(in) :: namespace
667 complex(real64), contiguous, intent(inout) :: pot(:)
668 complex(real64), contiguous, intent(in) :: rho(:)
669 logical, optional, intent(in) :: all_nodes
670 type(fourier_space_op_t), optional, intent(in) :: kernel
671
672 real(real64), allocatable :: aux1(:), aux2(:)
673 type(derivatives_t), pointer :: der
674 logical :: all_nodes_value
675 integer :: ip
676
677
678 der => this%der
679
681
682 call profiling_in('POISSON_RE_IM_SOLVE')
683
684 if (present(kernel) .and. der%periodic_dim>0) then
685 assert(.not. any(abs(kernel%qq(:))>1e-8_real64))
686 end if
687
688 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
689
690 safe_allocate(aux1(1:der%mesh%np))
691 safe_allocate(aux2(1:der%mesh%np))
692 ! first the real part
693 aux1(1:der%mesh%np) = real(rho(1:der%mesh%np), real64)
694 aux2(1:der%mesh%np) = real(pot(1:der%mesh%np), real64)
695 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
696 pot(1:der%mesh%np) = aux2(1:der%mesh%np)
697
698 ! now the imaginary part
699 aux1(1:der%mesh%np) = aimag(rho(1:der%mesh%np))
700 aux2(1:der%mesh%np) = aimag(pot(1:der%mesh%np))
701 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
702 !$omp parallel do
703 do ip = 1, der%mesh%np
704 pot(ip) = pot(ip) + m_zi*aux2(ip)
705 end do
706 !$omp end parallel do
707
708 safe_deallocate_a(aux1)
709 safe_deallocate_a(aux2)
710
711 call profiling_out('POISSON_RE_IM_SOLVE')
712
715
716 !-----------------------------------------------------------------
717
723 subroutine zpoisson_solve_real_and_imag_separately_batch(this, namespace, pot, rho, kernel)
724 type(poisson_t), intent(in) :: this
725 type(namespace_t), intent(in) :: namespace
726 complex(real64), contiguous, intent(out) :: pot(:, :)
727 complex(real64), contiguous, intent(in) :: rho(:, :)
728 type(fourier_space_op_t), optional, intent(in) :: kernel
729
730 real(real64), allocatable :: rwork(:, :), pwork(:, :)
731
733 call profiling_in('POISSON_RE_IM_SOLVE_BATCH')
734
735 if (present(kernel) .and. this%der%periodic_dim>0) then
736 assert(.not. any(abs(kernel%qq(:))>1e-8_real64))
737 end if
738
739 safe_allocate(rwork(1:size(rho, 1), 1:size(rho, 2)))
740 safe_allocate(pwork(1:size(pot, 1), 1:size(pot, 2)))
741
742 ! first the real part
743 rwork = real(rho, real64)
744 call dpoisson_solve_batch(this, namespace, pwork, rwork, kernel=kernel)
745 pot = pwork
746
747 ! now the imaginary part
748 rwork = aimag(rho)
749 call dpoisson_solve_batch(this, namespace, pwork, rwork, kernel=kernel)
750 pot = pot + m_zi*pwork
751
752 safe_deallocate_a(rwork)
753 safe_deallocate_a(pwork)
754
755 call profiling_out('POISSON_RE_IM_SOLVE_BATCH')
758
759 !-----------------------------------------------------------------
760
762 subroutine zpoisson_solve_real_and_imag_separately_accel(this, namespace, pot_buffer, rho_buffer, kernel, count)
763 type(poisson_t), intent(in) :: this
764 type(namespace_t), intent(in) :: namespace
765 type(accel_mem_t), intent(inout) :: pot_buffer
766 type(accel_mem_t), intent(in) :: rho_buffer
767 type(fourier_space_op_t), optional, intent(in) :: kernel
768 integer, optional, intent(in) :: count
769
770 type(accel_mem_t) :: re_in, im_in, re_out, im_out
771 type(accel_kernel_t), save :: kernel_split, kernel_merge
772 integer(int64) :: gsizes(3), bsizes(3)
773 integer :: np, count_, np_tot
774
776 call profiling_in('POISSON_RE_IM_ACCEL')
777
778 if (present(kernel)) then
779 assert(.not. any(abs(kernel%qq(:)) > 1e-8_real64))
780 end if
781
782 count_ = optional_default(count, 1)
783 np = this%der%mesh%np
784 np_tot = np * count_
785
786 call accel_create_buffer(re_in, accel_mem_read_write, type_float, int(np, int64) * count_)
787 call accel_create_buffer(im_in, accel_mem_read_write, type_float, int(np, int64) * count_)
788 call accel_create_buffer(re_out, accel_mem_read_write, type_float, int(np, int64) * count_)
789 call accel_create_buffer(im_out, accel_mem_read_write, type_float, int(np, int64) * count_)
790
791 ! split rho (complex) into its real and imaginary parts
792 call accel_kernel_start_call(kernel_split, 'split.cu', 'split_complex')
793 call accel_set_kernel_arg(kernel_split, 0, np_tot)
794 call accel_set_kernel_arg(kernel_split, 1, rho_buffer)
795 call accel_set_kernel_arg(kernel_split, 2, 0)
796 call accel_set_kernel_arg(kernel_split, 3, re_in)
797 call accel_set_kernel_arg(kernel_split, 4, 0)
798 call accel_set_kernel_arg(kernel_split, 5, im_in)
799 call accel_set_kernel_arg(kernel_split, 6, 0)
800 call accel_grid_size_extend_dim(int(np_tot, int64), 1_int64, gsizes, bsizes, kernel_split)
801 call accel_kernel_run(kernel_split, gsizes, bsizes)
802 call accel_finish()
804 ! solve the real and imaginary parts on the real cube with the batched solver.
805 call dpoisson_solve_batch(this, namespace, pot_buffer=re_out, rho_buffer=re_in, kernel=kernel, count=count_)
806 call dpoisson_solve_batch(this, namespace, pot_buffer=im_out, rho_buffer=im_in, kernel=kernel, count=count_)
807
808 ! recombine pot = re_out + i*im_out
809 call accel_kernel_start_call(kernel_merge, 'split.cu', 'merge_complex')
810 call accel_set_kernel_arg(kernel_merge, 0, np_tot)
811 call accel_set_kernel_arg(kernel_merge, 1, re_out)
812 call accel_set_kernel_arg(kernel_merge, 2, 0)
813 call accel_set_kernel_arg(kernel_merge, 3, im_out)
814 call accel_set_kernel_arg(kernel_merge, 4, 0)
815 call accel_set_kernel_arg(kernel_merge, 5, pot_buffer)
816 call accel_set_kernel_arg(kernel_merge, 6, 0)
817 call accel_grid_size_extend_dim(int(np_tot, int64), 1_int64, gsizes, bsizes, kernel_merge)
818 call accel_kernel_run(kernel_merge, gsizes, bsizes)
819 call accel_finish()
820
821 call accel_free_buffer(re_in)
822 call accel_free_buffer(im_in)
823 call accel_free_buffer(re_out)
824 call accel_free_buffer(im_out)
825
826 call profiling_out('POISSON_RE_IM_ACCEL')
829
830 !-----------------------------------------------------------------
831
832 subroutine zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
833 type(poisson_t), intent(in) :: this
834 type(namespace_t), intent(in) :: namespace
835 complex(real64), contiguous, intent(inout) :: pot(:)
836 complex(real64), contiguous, intent(in) :: rho(:)
837 logical, optional, intent(in) :: all_nodes
838 type(fourier_space_op_t), optional, intent(in) :: kernel
839 logical, optional, intent(in) :: reset
840
841 logical :: all_nodes_value
843 push_sub(zpoisson_solve)
844
845 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
846
847 assert(ubound(pot, dim = 1) == this%der%mesh%np_part .or. ubound(pot, dim = 1) == this%der%mesh%np)
848 assert(ubound(rho, dim = 1) == this%der%mesh%np_part .or. ubound(rho, dim = 1) == this%der%mesh%np)
849
850 assert(this%method /= poisson_null)
851
852 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
853 pot(1:this%der%mesh%np) = m_zero
854 end if
855
856 if (this%method == poisson_fft .and. this%kernel /= poisson_fft_kernel_corrected &
857 .and. .not. this%is_dressed) then
858 !The default (real) Poisson solver is used for OEP and Sternheimer calls were we do not need
859 !a complex-to-xomplex FFT as these parts use the normal Coulomb potential
860 if (this%cube%fft%type == fft_complex) then
861 !We add the profiling here, as the other path uses dpoisson_solve
862 call profiling_in('ZPOISSON_SOLVE')
863 call zpoisson_fft_solve(this%fft_solver, this%der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
864 call profiling_out('ZPOISSON_SOLVE')
865 else
866 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel=kernel)
867 end if
868 else
869 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel = kernel)
870 end if
871
872 pop_sub(zpoisson_solve)
873 end subroutine zpoisson_solve
874
875
876 !-----------------------------------------------------------------
877
878 subroutine poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
879 type(poisson_t), intent(inout) :: this
880 type(namespace_t), intent(in) :: namespace
881 type(batch_t), intent(inout) :: potb
882 type(batch_t), intent(inout) :: rhob
883 logical, optional, intent(in) :: all_nodes
884 type(fourier_space_op_t), optional, intent(in) :: kernel
885
886 integer :: ii
887
888 push_sub(poisson_solve_batch)
889
890 assert(potb%nst_linear == rhob%nst_linear)
891 assert(potb%type() == rhob%type())
892
893 if (potb%type() == type_float) then
894 do ii = 1, potb%nst_linear
895 call dpoisson_solve(this, namespace, potb%dff_linear(:, ii), rhob%dff_linear(:, ii), all_nodes, kernel=kernel)
896 end do
897 else
898 do ii = 1, potb%nst_linear
899 call zpoisson_solve(this, namespace, potb%zff_linear(:, ii), rhob%zff_linear(:, ii), all_nodes, kernel=kernel)
900 end do
901 end if
902
903 pop_sub(poisson_solve_batch)
904 end subroutine poisson_solve_batch
905
906 !-----------------------------------------------------------------
912 logical function poisson_is_batch_capable(this)
913 type(poisson_t), intent(in) :: this
914
915 poisson_is_batch_capable = this%method == poisson_fft &
916 .and. this%kernel /= poisson_fft_kernel_corrected
917 end function poisson_is_batch_capable
918
919 !-----------------------------------------------------------------
921 logical function poisson_is_device_batch_capable(this)
922 type(poisson_t), intent(in) :: this
923
924 ! Tested in steps: only a batch-capable solver is guaranteed to have an FFT cube.
926 if (.not. accel_is_enabled()) return
927 if (.not. poisson_is_batch_capable(this)) return
928 poisson_is_device_batch_capable = this%cube%fft%library == fftlib_accel &
929 .and. .not. this%cube%parallel_in_domains
931
932 !-----------------------------------------------------------------
933
939 subroutine dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
940 type(poisson_t), intent(in) :: this
941 type(namespace_t), intent(in) :: namespace
942 real(real64), contiguous, intent(inout) :: pot(:)
943 real(real64), contiguous, intent(in) :: rho(:)
947 logical, optional, intent(in) :: all_nodes
948 type(fourier_space_op_t), optional, intent(in) :: kernel
949 logical, optional, intent(in) :: reset
950
951 type(derivatives_t), pointer :: der
952 real(real64), allocatable :: rho_corrected(:), vh_correction(:)
953 logical :: all_nodes_value
954
955 call profiling_in('POISSON_SOLVE')
956 push_sub(dpoisson_solve)
957
958 der => this%der
959
960 assert(ubound(pot, dim = 1) == der%mesh%np_part .or. ubound(pot, dim = 1) == der%mesh%np)
961 assert(ubound(rho, dim = 1) == der%mesh%np_part .or. ubound(rho, dim = 1) == der%mesh%np)
962
963 ! Check optional argument and set to default if necessary.
964 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
965
966 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
967 pot(1:der%mesh%np) = m_zero
968 end if
969
970 assert(this%method /= poisson_null)
971
972 if (present(kernel)) then
973 assert(this%method == poisson_fft)
974 end if
975
976 select case (this%method)
977 case (poisson_direct_sum)
978 if ((this%is_dressed .and. this%der%dim - 1 > 3) .or. this%der%dim > 3) then
979 message(1) = "Direct sum Poisson solver only available for 1, 2, or 3 dimensions."
980 call messages_fatal(1, namespace=namespace)
981 end if
982 call poisson_solve_direct(this, namespace, pot, rho)
983
984 case (poisson_cg)
985 call poisson_cg1(namespace, der, this%corrector, pot, rho)
986
988 safe_allocate(rho_corrected(1:der%mesh%np))
989 safe_allocate(vh_correction(1:der%mesh%np_part))
990
991 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
993 call lalg_axpy(der%mesh%np, -m_one, vh_correction, pot)
994 call poisson_cg2(namespace, der, pot, rho_corrected)
995 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
996
997 safe_deallocate_a(rho_corrected)
998 safe_deallocate_a(vh_correction)
999
1000 case (poisson_multigrid)
1001 call poisson_multigrid_solver(this%mg, namespace, der, pot, rho)
1002
1003 case (poisson_fft)
1004 if (this%kernel /= poisson_fft_kernel_corrected) then
1005 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
1006 else
1007 safe_allocate(rho_corrected(1:der%mesh%np))
1008 safe_allocate(vh_correction(1:der%mesh%np_part))
1009
1010 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
1011 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho_corrected, this%mesh_cube_map, &
1012 average_to_zero = .true., kernel=kernel)
1013
1014 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
1015 safe_deallocate_a(rho_corrected)
1016 safe_deallocate_a(vh_correction)
1017 end if
1018
1020 call poisson_isf_solve(this%isf_solver, der%mesh, this%cube, pot, rho, all_nodes_value)
1021
1022
1023 case (poisson_psolver)
1024 if (this%psolver_solver%datacode == "G") then
1025 ! Global version
1026 call poisson_psolver_global_solve(this%psolver_solver, der%mesh, this%cube, pot, rho)
1027 else ! "D" Distributed version
1028 call poisson_psolver_parallel_solve(this%psolver_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map)
1029 end if
1030
1031 case (poisson_no)
1032 call poisson_no_solve(this%no_solver, der%mesh, pot, rho)
1033 end select
1034
1035 ! Add extra terms for dressed interaction
1036 if (this%is_dressed .and. this%method /= poisson_no) then
1037 call photon_mode_add_poisson_terms(this%photons, der%mesh, rho, pot)
1038 end if
1039
1040 pop_sub(dpoisson_solve)
1041 call profiling_out('POISSON_SOLVE')
1042 end subroutine dpoisson_solve
1043
1044 !-----------------------------------------------------------------
1045 subroutine poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
1046 type(poisson_t), intent(inout) :: this
1047 type(namespace_t), intent(in) :: namespace
1048 class(space_t), intent(in) :: space
1049 type(poisson_t), intent(in) :: main
1050 type(derivatives_t), target, intent(in) :: der
1051 type(submesh_t), intent(inout) :: sm
1052 type(mpi_grp_t), intent(in) :: grp
1053 integer, optional, intent(in) :: method
1054 logical, optional, intent(in) :: force_cmplx
1055
1056 integer :: default_solver, idir, iter, maxl
1057 integer :: box(space%dim)
1058 real(real64) :: qq(der%dim), threshold
1059
1060 if (this%method /= poisson_null) return ! already initialized
1061
1062 push_sub(poisson_init_sm)
1063
1064 this%is_dressed = .false.
1065 !TODO: To be implemented as an option
1066 this%all_nodes_default = .false.
1067
1068 this%nslaves = 0
1069 this%der => der
1070
1071#ifdef HAVE_MPI
1072 this%all_nodes_default = main%all_nodes_default
1073#endif
1074
1075 default_solver = poisson_direct_sum
1076 this%method = default_solver
1077 if (present(method)) this%method = method
1078
1079 if (der%mesh%use_curvilinear) then
1080 call messages_not_implemented("Submesh Poisson solver with curvilinear mesh", namespace=namespace)
1081 end if
1082
1083 this%kernel = poisson_fft_kernel_none
1084
1085 select case (this%method)
1086 case (poisson_direct_sum)
1087 !Nothing to be done
1088
1089 case (poisson_isf)
1090 !TODO: Add support for domain parrallelization
1091 assert(.not. der%mesh%parallel_in_domains)
1092 call submesh_get_cube_dim(sm, space, box)
1093 call submesh_init_cube_map(sm, space)
1094 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1095 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1096 call cube_init_cube_map(this%cube, sm%mesh)
1097 call poisson_isf_init(this%isf_solver, namespace, der%mesh, this%cube, grp%comm, init_world = this%all_nodes_default)
1098
1099 case (poisson_psolver)
1100 !TODO: Add support for domain parrallelization
1101 assert(.not. der%mesh%parallel_in_domains)
1102 if (this%all_nodes_default) then
1103 this%cube%mpi_grp = grp
1104 else
1105 this%cube%mpi_grp = this%der%mesh%mpi_grp
1106 end if
1107 call submesh_get_cube_dim(sm, space, box)
1108 call submesh_init_cube_map(sm, space)
1109 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1110 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1111 call cube_init_cube_map(this%cube, sm%mesh)
1112 qq = m_zero
1113 call poisson_psolver_init(this%psolver_solver, namespace, space, this%cube, m_zero, qq, force_isolated=.true.)
1114 call poisson_psolver_get_dims(this%psolver_solver, this%cube)
1115 case (poisson_fft)
1116 !Here we impose zero boundary conditions
1117 this%kernel = poisson_fft_kernel_sph
1118 !We need to parse this, in case this routine is called before poisson_init
1119 call parse_variable(namespace, 'FFTLibrary', fftlib_fftw, fft_default_lib)
1120
1121 call submesh_get_cube_dim(sm, space, box)
1122 call submesh_init_cube_map(sm, space)
1123 !We double the size of the cell
1124 !Maybe the factor of two should be controlled as a variable
1125 do idir = 1, space%dim
1126 box(idir) = (2 * (box(idir) - 1)) + 1
1127 end do
1128 if (optional_default(force_cmplx, .false.)) then
1129 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1130 fft_type = fft_complex, need_partition=.not.der%mesh%parallel_in_domains)
1131 else
1132 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1133 fft_type = fft_real, need_partition=.not.der%mesh%parallel_in_domains)
1134 end if
1135 call poisson_fft_init(this%fft_solver, namespace, space, this%cube, this%kernel)
1136 case (poisson_cg)
1137 call parse_variable(namespace, 'PoissonSolverMaxMultipole', 4, maxl)
1138 write(message(1),'(a,i2)')'Info: Boundary conditions fixed up to L =', maxl
1139 call messages_info(1, namespace=namespace)
1140 call parse_variable(namespace, 'PoissonSolverMaxIter', 500, iter)
1141 call parse_variable(namespace, 'PoissonSolverThreshold', 1.0e-6_real64, threshold)
1142 call poisson_corrections_init(this%corrector, namespace, space, maxl, this%der%mesh)
1143 call poisson_cg_init(threshold, iter)
1144 end select
1145
1146 pop_sub(poisson_init_sm)
1147 end subroutine poisson_init_sm
1148
1149 ! -----------------------------------------------------------------
1150
1151 logical pure function poisson_solver_is_iterative(this) result(iterative)
1152 type(poisson_t), intent(in) :: this
1153
1154 iterative = this%method == poisson_cg .or. this%method == poisson_cg_corrected
1155 end function poisson_solver_is_iterative
1156
1157 !-----------------------------------------------------------------
1158 subroutine poisson_async_init(this, mc)
1159 type(poisson_t), intent(inout) :: this
1160 type(multicomm_t), intent(in) :: mc
1161
1162 push_sub(poisson_async_init)
1163
1164#ifdef HAVE_MPI
1165 if (multicomm_have_slaves(mc)) then
1166
1167 call mpi_grp_init(this%local_grp, mc%group_comm(p_strategy_states))
1168
1169 this%root = (this%local_grp%is_root())
1170
1171 this%intercomm = mc%slave_intercomm
1172 call mpi_comm_remote_size(this%intercomm, this%nslaves)
1173
1174 end if
1175#endif
1176
1177 pop_sub(poisson_async_init)
1178
1179 end subroutine poisson_async_init
1180
1181 !-----------------------------------------------------------------
1182
1183 subroutine poisson_async_end(this, mc)
1184 type(poisson_t), intent(inout) :: this
1185 type(multicomm_t), intent(in) :: mc
1186
1187#ifdef HAVE_MPI
1188 integer :: islave
1189#endif
1190
1191 push_sub(poisson_async_end)
1192
1193#ifdef HAVE_MPI
1194 if (multicomm_have_slaves(mc)) then
1195
1196 ! send the finish signal
1197 do islave = this%local_grp%rank, this%nslaves - 1, this%local_grp%size
1198 call mpi_send(m_one, 1, mpi_double_precision, islave, cmd_finish, this%intercomm)
1199 end do
1200
1201 end if
1202#endif
1203
1204 pop_sub(poisson_async_end)
1205
1206 end subroutine poisson_async_end
1207
1208 !-----------------------------------------------------------------
1209
1210 subroutine poisson_slave_work(this, namespace)
1211 type(poisson_t), intent(inout) :: this
1212 type(namespace_t), intent(in) :: namespace
1213
1214#ifdef HAVE_MPI
1215 real(real64), allocatable :: rho(:), pot(:)
1216 logical :: done
1217 type(mpi_status) :: status
1218 integer :: bcast_root
1219
1220 push_sub(poisson_slave_work)
1221 call profiling_in("SLAVE_WORK")
1222
1223 safe_allocate(rho(1:this%der%mesh%np))
1224 safe_allocate(pot(1:this%der%mesh%np))
1225 done = .false.
1226
1227 do while(.not. done)
1228
1229 call profiling_in("SLAVE_WAIT")
1230 call mpi_recv(rho(1), this%der%mesh%np, mpi_double_precision, mpi_any_source, mpi_any_tag, this%intercomm, status)
1231 call profiling_out("SLAVE_WAIT")
1232
1233 ! The tag of the message tells us what we have to do.
1234 select case (status%MPI_TAG)
1235
1236 case (cmd_finish)
1237 done = .true.
1239 case (cmd_poisson_solve)
1240 call dpoisson_solve(this, namespace, pot, rho)
1241
1242 call profiling_in("SLAVE_BROADCAST")
1243 bcast_root = mpi_proc_null
1244 if (this%root) bcast_root = mpi_root
1245 call mpi_bcast(pot(1), this%der%mesh%np, mpi_double_precision, bcast_root, this%intercomm)
1246 call profiling_out("SLAVE_BROADCAST")
1247
1248 end select
1249
1250 end do
1251
1252 safe_deallocate_a(pot)
1253 safe_deallocate_a(rho)
1254
1255 call profiling_out("SLAVE_WORK")
1256 pop_sub(poisson_slave_work)
1257#endif
1258 end subroutine poisson_slave_work
1259
1260 !----------------------------------------------------------------
1261
1262 logical pure function poisson_is_async(this) result(async)
1263 type(poisson_t), intent(in) :: this
1264
1265 async = (this%nslaves > 0)
1267 end function poisson_is_async
1268
1269 !----------------------------------------------------------------
1270
1271 subroutine poisson_build_kernel(this, namespace, space, coulb, qq, cam, singul)
1272 type(poisson_t), intent(in) :: this
1273 type(namespace_t), intent(in) :: namespace
1274 class(space_t), intent(in) :: space
1275 type(fourier_space_op_t), intent(inout) :: coulb
1276 real(real64), intent(in) :: qq(:)
1277 type(xc_cam_t), intent(in) :: cam
1278 real(real64), optional, intent(in) :: singul
1279
1280 logical :: reinit
1281
1282 push_sub(poisson_build_kernel)
1284 if (space%is_periodic()) then
1285 assert(ubound(qq, 1) >= space%periodic_dim)
1286 assert(this%method == poisson_fft)
1287 end if
1288
1289 if (cam%omega > m_epsilon) then
1290 if (this%method /= poisson_fft) then
1291 write(message(1),'(a)') "Poisson solver with range separation is only implemented with FFT."
1292 call messages_fatal(1, namespace=namespace)
1293 end if
1294 end if
1295
1296 !We only reinitialize the poisson solver if needed
1297 reinit = .false.
1298 if (allocated(coulb%qq)) then
1299 reinit = any(abs(coulb%qq(1:space%periodic_dim) - qq(1:space%periodic_dim)) > m_epsilon)
1300 end if
1301 reinit = reinit .or. (abs(coulb%mu - cam%omega) > m_epsilon .and. cam%omega > m_epsilon)
1302 reinit = reinit .or. (abs(coulb%alpha - cam%alpha) > m_epsilon .and. cam%alpha > m_epsilon)
1303 reinit = reinit .or. (abs(coulb%beta - cam%beta) > m_epsilon .and. cam%beta > m_epsilon)
1304
1305 if (reinit) then
1306 call profiling_in('POISSON_BUILD_KERNEL')
1307 !TODO: this should be a select case supporting other kernels.
1308 ! This means that we need an abstract object for kernels.
1309 select case (this%method)
1310 case (poisson_fft)
1311 ! Check that we are consistent: the Poisson solver supports must return 1 here
1312 assert(is_close(poisson_get_full_range_weight(this, cam), m_one))
1313 call fourier_space_op_end(coulb)
1314 call coulb%init(space, qq, cam, singul)
1315 call poisson_fft_get_kernel(namespace, space, this%cube, coulb, this%kernel, &
1316 this%poisson_soft_coulomb_param)
1317 case default
1318 call messages_not_implemented("poisson_build_kernel with other methods than FFT", namespace=namespace)
1319 end select
1320 call profiling_out('POISSON_BUILD_KERNEL')
1321 end if
1322
1323 pop_sub(poisson_build_kernel)
1324 end subroutine poisson_build_kernel
1325
1326 !----------------------------------------------------------------
1335 real(real64) function poisson_get_full_range_weight(this, cam) result(weight)
1336 type(poisson_t), intent(in) :: this
1337 type(xc_cam_t), intent(in) :: cam
1338
1339 select case (this%method)
1340 case (poisson_fft)
1341 weight = m_one
1342 case default
1343 if(cam%omega < m_epsilon) then
1344 weight = cam%alpha
1345 else if(cam%alpha > m_epsilon .and. cam%beta < m_epsilon) then
1346 weight = cam%alpha
1347 else if(cam%alpha < m_epsilon .and. cam%beta > m_epsilon) then
1348 weight = cam%beta
1349 else
1350 assert(.false.)
1351 end if
1352 end select
1354
1355#include "poisson_init_inc.F90"
1356#include "poisson_direct_inc.F90"
1357#include "poisson_direct_sm_inc.F90"
1358
1359#include "undef.F90"
1360#include "real.F90"
1361#include "poisson_inc.F90"
1362#include "undef.F90"
1363#include "complex.F90"
1364#include "poisson_inc.F90"
1365
1366end module poisson_oct_m
1367
1368!! Local Variables:
1369!! mode: f90
1370!! coding: utf-8
1371!! 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:1006
subroutine, public accel_kernel_start_call(this, file_name, kernel_name, flags)
Definition: accel.F90:1439
subroutine, public accel_finish()
Definition: accel.F90:1124
integer, parameter, public accel_mem_read_write
Definition: accel.F90:186
pure logical function, public accel_is_enabled()
Definition: accel.F90:403
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)
Definition: cube.F90:209
subroutine, public cube_init_cube_map(cube, mesh)
Definition: cube.F90:881
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:2429
integer, parameter, public poisson_multigrid
Definition: poisson.F90:191
subroutine poisson_kernel_init(this, namespace, space, mc, stencil)
Definition: poisson.F90:1388
integer, parameter, public poisson_psolver
Definition: poisson.F90:191
subroutine, public dpoisson_solve_start(this, rho)
Definition: poisson.F90:2153
integer, parameter cmd_finish
Definition: poisson.F90:227
subroutine, public zpoisson_solve_finish(this, pot)
Definition: poisson.F90:2417
subroutine poisson_solve_direct(this, namespace, pot, rho)
Definition: poisson.F90:1599
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:2564
subroutine, public zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Definition: poisson.F90:913
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
Definition: poisson.F90:1126
subroutine, public poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
Definition: poisson.F90:959
subroutine, public poisson_async_init(this, mc)
Definition: poisson.F90:1239
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:2173
subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
Definition: poisson.F90:745
logical pure function poisson_solver_is_iterative(this)
Definition: poisson.F90:1232
subroutine, public poisson_slave_work(this, namespace)
Definition: poisson.F90:1267
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:843
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:1020
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:1284
subroutine, public dpoisson_solve_finish(this, pot)
Definition: poisson.F90:2161
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:2409
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:804
subroutine, public poisson_async_end(this, mc)
Definition: poisson.F90:1251
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:1002
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:1348
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:2252
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:1275
subroutine, public poisson_end(this)
Definition: poisson.F90:692
logical function poisson_is_batch_capable(this)
Whether this solver can transform a whole batch of functions in one call.
Definition: poisson.F90:993
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
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)