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
803 ! solve the real and imaginary parts on the real cube with the batched solver.
804 call dpoisson_solve_batch(this, namespace, pot_buffer=re_out, rho_buffer=re_in, kernel=kernel, count=count_)
805 call dpoisson_solve_batch(this, namespace, pot_buffer=im_out, rho_buffer=im_in, kernel=kernel, count=count_)
806
807 ! recombine pot = re_out + i*im_out
808 call accel_kernel_start_call(kernel_merge, 'split.cu', 'merge_complex')
809 call accel_set_kernel_arg(kernel_merge, 0, np_tot)
810 call accel_set_kernel_arg(kernel_merge, 1, re_out)
811 call accel_set_kernel_arg(kernel_merge, 2, 0)
812 call accel_set_kernel_arg(kernel_merge, 3, im_out)
813 call accel_set_kernel_arg(kernel_merge, 4, 0)
814 call accel_set_kernel_arg(kernel_merge, 5, pot_buffer)
815 call accel_set_kernel_arg(kernel_merge, 6, 0)
816 call accel_grid_size_extend_dim(int(np_tot, int64), 1_int64, gsizes, bsizes, kernel_merge)
817 call accel_kernel_run(kernel_merge, gsizes, bsizes)
818 call accel_finish()
819
820 call accel_free_buffer(re_in)
821 call accel_free_buffer(im_in)
822 call accel_free_buffer(re_out)
823 call accel_free_buffer(im_out)
824
825 call profiling_out('POISSON_RE_IM_ACCEL')
828
829 !-----------------------------------------------------------------
830
831 subroutine zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
832 type(poisson_t), intent(in) :: this
833 type(namespace_t), intent(in) :: namespace
834 complex(real64), contiguous, intent(inout) :: pot(:)
835 complex(real64), contiguous, intent(in) :: rho(:)
836 logical, optional, intent(in) :: all_nodes
837 type(fourier_space_op_t), optional, intent(in) :: kernel
838 logical, optional, intent(in) :: reset
839
840 logical :: all_nodes_value
841
843
844 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
845
846 assert(ubound(pot, dim = 1) == this%der%mesh%np_part .or. ubound(pot, dim = 1) == this%der%mesh%np)
847 assert(ubound(rho, dim = 1) == this%der%mesh%np_part .or. ubound(rho, dim = 1) == this%der%mesh%np)
848
849 assert(this%method /= poisson_null)
850
851 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
852 pot(1:this%der%mesh%np) = m_zero
853 end if
854
855 if (this%method == poisson_fft .and. this%kernel /= poisson_fft_kernel_corrected &
856 .and. .not. this%is_dressed) then
857 !The default (real) Poisson solver is used for OEP and Sternheimer calls were we do not need
858 !a complex-to-xomplex FFT as these parts use the normal Coulomb potential
859 if (this%cube%fft%type == fft_complex) then
860 !We add the profiling here, as the other path uses dpoisson_solve
861 call profiling_in('ZPOISSON_SOLVE')
862 call zpoisson_fft_solve(this%fft_solver, this%der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
863 call profiling_out('ZPOISSON_SOLVE')
864 else
865 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel=kernel)
866 end if
867 else
868 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel = kernel)
869 end if
870
871 pop_sub(zpoisson_solve)
872 end subroutine zpoisson_solve
873
874
875 !-----------------------------------------------------------------
876
877 subroutine poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
878 type(poisson_t), intent(inout) :: this
879 type(namespace_t), intent(in) :: namespace
880 type(batch_t), intent(inout) :: potb
881 type(batch_t), intent(inout) :: rhob
882 logical, optional, intent(in) :: all_nodes
883 type(fourier_space_op_t), optional, intent(in) :: kernel
884
885 integer :: ii
886
887 push_sub(poisson_solve_batch)
888
889 assert(potb%nst_linear == rhob%nst_linear)
890 assert(potb%type() == rhob%type())
891
892 if (potb%type() == type_float) then
893 do ii = 1, potb%nst_linear
894 call dpoisson_solve(this, namespace, potb%dff_linear(:, ii), rhob%dff_linear(:, ii), all_nodes, kernel=kernel)
895 end do
896 else
897 do ii = 1, potb%nst_linear
898 call zpoisson_solve(this, namespace, potb%zff_linear(:, ii), rhob%zff_linear(:, ii), all_nodes, kernel=kernel)
899 end do
900 end if
901
902 pop_sub(poisson_solve_batch)
903 end subroutine poisson_solve_batch
904
905 !-----------------------------------------------------------------
911 logical function poisson_is_batch_capable(this)
912 type(poisson_t), intent(in) :: this
913
914 poisson_is_batch_capable = this%method == poisson_fft &
915 .and. this%kernel /= poisson_fft_kernel_corrected
916 end function poisson_is_batch_capable
917
918 !-----------------------------------------------------------------
920 logical function poisson_is_device_batch_capable(this)
921 type(poisson_t), intent(in) :: this
922
923 ! Tested in steps: only a batch-capable solver is guaranteed to have an FFT cube.
925 if (.not. accel_is_enabled()) return
926 if (.not. poisson_is_batch_capable(this)) return
927 poisson_is_device_batch_capable = this%cube%fft%library == fftlib_accel &
928 .and. .not. this%cube%parallel_in_domains
930
931 !-----------------------------------------------------------------
932
938 subroutine dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
939 type(poisson_t), intent(in) :: this
940 type(namespace_t), intent(in) :: namespace
941 real(real64), contiguous, intent(inout) :: pot(:)
942 real(real64), contiguous, intent(in) :: rho(:)
946 logical, optional, intent(in) :: all_nodes
947 type(fourier_space_op_t), optional, intent(in) :: kernel
948 logical, optional, intent(in) :: reset
949
950 type(derivatives_t), pointer :: der
951 real(real64), allocatable :: rho_corrected(:), vh_correction(:)
952 logical :: all_nodes_value
953
954 call profiling_in('POISSON_SOLVE')
955 push_sub(dpoisson_solve)
956
957 der => this%der
958
959 assert(ubound(pot, dim = 1) == der%mesh%np_part .or. ubound(pot, dim = 1) == der%mesh%np)
960 assert(ubound(rho, dim = 1) == der%mesh%np_part .or. ubound(rho, dim = 1) == der%mesh%np)
961
962 ! Check optional argument and set to default if necessary.
963 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
964
965 if (poisson_solver_is_iterative(this) .and. optional_default(reset, .true.)) then
966 pot(1:der%mesh%np) = m_zero
967 end if
968
969 assert(this%method /= poisson_null)
970
971 if (present(kernel)) then
972 assert(this%method == poisson_fft)
973 end if
974
975 select case (this%method)
976 case (poisson_direct_sum)
977 if ((this%is_dressed .and. this%der%dim - 1 > 3) .or. this%der%dim > 3) then
978 message(1) = "Direct sum Poisson solver only available for 1, 2, or 3 dimensions."
979 call messages_fatal(1, namespace=namespace)
980 end if
981 call poisson_solve_direct(this, namespace, pot, rho)
982
983 case (poisson_cg)
984 call poisson_cg1(namespace, der, this%corrector, pot, rho)
985
987 safe_allocate(rho_corrected(1:der%mesh%np))
988 safe_allocate(vh_correction(1:der%mesh%np_part))
989
990 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
992 call lalg_axpy(der%mesh%np, -m_one, vh_correction, pot)
993 call poisson_cg2(namespace, der, pot, rho_corrected)
994 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
995
996 safe_deallocate_a(rho_corrected)
997 safe_deallocate_a(vh_correction)
998
999 case (poisson_multigrid)
1000 call poisson_multigrid_solver(this%mg, namespace, der, pot, rho)
1001
1002 case (poisson_fft)
1003 if (this%kernel /= poisson_fft_kernel_corrected) then
1004 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
1005 else
1006 safe_allocate(rho_corrected(1:der%mesh%np))
1007 safe_allocate(vh_correction(1:der%mesh%np_part))
1008
1009 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
1010 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho_corrected, this%mesh_cube_map, &
1011 average_to_zero = .true., kernel=kernel)
1012
1013 call lalg_axpy(der%mesh%np, m_one, vh_correction, pot)
1014 safe_deallocate_a(rho_corrected)
1015 safe_deallocate_a(vh_correction)
1016 end if
1017
1019 call poisson_isf_solve(this%isf_solver, der%mesh, this%cube, pot, rho, all_nodes_value)
1020
1021
1022 case (poisson_psolver)
1023 if (this%psolver_solver%datacode == "G") then
1024 ! Global version
1025 call poisson_psolver_global_solve(this%psolver_solver, der%mesh, this%cube, pot, rho)
1026 else ! "D" Distributed version
1027 call poisson_psolver_parallel_solve(this%psolver_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map)
1028 end if
1029
1030 case (poisson_no)
1031 call poisson_no_solve(this%no_solver, der%mesh, pot, rho)
1032 end select
1033
1034 ! Add extra terms for dressed interaction
1035 if (this%is_dressed .and. this%method /= poisson_no) then
1036 call photon_mode_add_poisson_terms(this%photons, der%mesh, rho, pot)
1037 end if
1038
1039 pop_sub(dpoisson_solve)
1040 call profiling_out('POISSON_SOLVE')
1041 end subroutine dpoisson_solve
1042
1043 !-----------------------------------------------------------------
1044 subroutine poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
1045 type(poisson_t), intent(inout) :: this
1046 type(namespace_t), intent(in) :: namespace
1047 class(space_t), intent(in) :: space
1048 type(poisson_t), intent(in) :: main
1049 type(derivatives_t), target, intent(in) :: der
1050 type(submesh_t), intent(inout) :: sm
1051 type(mpi_grp_t), intent(in) :: grp
1052 integer, optional, intent(in) :: method
1053 logical, optional, intent(in) :: force_cmplx
1054
1055 integer :: default_solver, idir, iter, maxl
1056 integer :: box(space%dim)
1057 real(real64) :: qq(der%dim), threshold
1058
1059 if (this%method /= poisson_null) return ! already initialized
1060
1061 push_sub(poisson_init_sm)
1062
1063 this%is_dressed = .false.
1064 !TODO: To be implemented as an option
1065 this%all_nodes_default = .false.
1066
1067 this%nslaves = 0
1068 this%der => der
1069
1070#ifdef HAVE_MPI
1071 this%all_nodes_default = main%all_nodes_default
1072#endif
1073
1074 default_solver = poisson_direct_sum
1075 this%method = default_solver
1076 if (present(method)) this%method = method
1077
1078 if (der%mesh%use_curvilinear) then
1079 call messages_not_implemented("Submesh Poisson solver with curvilinear mesh", namespace=namespace)
1080 end if
1081
1082 this%kernel = poisson_fft_kernel_none
1083
1084 select case (this%method)
1085 case (poisson_direct_sum)
1086 !Nothing to be done
1087
1088 case (poisson_isf)
1089 !TODO: Add support for domain parrallelization
1090 assert(.not. der%mesh%parallel_in_domains)
1091 call submesh_get_cube_dim(sm, space, box)
1092 call submesh_init_cube_map(sm, space)
1093 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1094 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1095 call cube_init_cube_map(this%cube, sm%mesh)
1096 call poisson_isf_init(this%isf_solver, namespace, der%mesh, this%cube, grp%comm, init_world = this%all_nodes_default)
1097
1098 case (poisson_psolver)
1099 !TODO: Add support for domain parrallelization
1100 assert(.not. der%mesh%parallel_in_domains)
1101 if (this%all_nodes_default) then
1102 this%cube%mpi_grp = grp
1103 else
1104 this%cube%mpi_grp = this%der%mesh%mpi_grp
1105 end if
1106 call submesh_get_cube_dim(sm, space, box)
1107 call submesh_init_cube_map(sm, space)
1108 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1109 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
1110 call cube_init_cube_map(this%cube, sm%mesh)
1111 qq = m_zero
1112 call poisson_psolver_init(this%psolver_solver, namespace, space, this%cube, m_zero, qq, force_isolated=.true.)
1113 call poisson_psolver_get_dims(this%psolver_solver, this%cube)
1114 case (poisson_fft)
1115 !Here we impose zero boundary conditions
1116 this%kernel = poisson_fft_kernel_sph
1117 !We need to parse this, in case this routine is called before poisson_init
1118 call parse_variable(namespace, 'FFTLibrary', fftlib_fftw, fft_default_lib)
1119
1120 call submesh_get_cube_dim(sm, space, box)
1121 call submesh_init_cube_map(sm, space)
1122 !We double the size of the cell
1123 !Maybe the factor of two should be controlled as a variable
1124 do idir = 1, space%dim
1125 box(idir) = (2 * (box(idir) - 1)) + 1
1126 end do
1127 if (optional_default(force_cmplx, .false.)) then
1128 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1129 fft_type = fft_complex, need_partition=.not.der%mesh%parallel_in_domains)
1130 else
1131 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
1132 fft_type = fft_real, need_partition=.not.der%mesh%parallel_in_domains)
1133 end if
1134 call poisson_fft_init(this%fft_solver, namespace, space, this%cube, this%kernel)
1135 case (poisson_cg)
1136 call parse_variable(namespace, 'PoissonSolverMaxMultipole', 4, maxl)
1137 write(message(1),'(a,i2)')'Info: Boundary conditions fixed up to L =', maxl
1138 call messages_info(1, namespace=namespace)
1139 call parse_variable(namespace, 'PoissonSolverMaxIter', 500, iter)
1140 call parse_variable(namespace, 'PoissonSolverThreshold', 1.0e-6_real64, threshold)
1141 call poisson_corrections_init(this%corrector, namespace, space, maxl, this%der%mesh)
1142 call poisson_cg_init(threshold, iter)
1143 end select
1144
1145 pop_sub(poisson_init_sm)
1146 end subroutine poisson_init_sm
1147
1148 ! -----------------------------------------------------------------
1149
1150 logical pure function poisson_solver_is_iterative(this) result(iterative)
1151 type(poisson_t), intent(in) :: this
1152
1153 iterative = this%method == poisson_cg .or. this%method == poisson_cg_corrected
1154 end function poisson_solver_is_iterative
1155
1156 !-----------------------------------------------------------------
1157 subroutine poisson_async_init(this, mc)
1158 type(poisson_t), intent(inout) :: this
1159 type(multicomm_t), intent(in) :: mc
1160
1161 push_sub(poisson_async_init)
1162
1163#ifdef HAVE_MPI
1164 if (multicomm_have_slaves(mc)) then
1165
1166 call mpi_grp_init(this%local_grp, mc%group_comm(p_strategy_states))
1167
1168 this%root = (this%local_grp%is_root())
1169
1170 this%intercomm = mc%slave_intercomm
1171 call mpi_comm_remote_size(this%intercomm, this%nslaves)
1172
1173 end if
1174#endif
1175
1176 pop_sub(poisson_async_init)
1177
1178 end subroutine poisson_async_init
1179
1180 !-----------------------------------------------------------------
1181
1182 subroutine poisson_async_end(this, mc)
1183 type(poisson_t), intent(inout) :: this
1184 type(multicomm_t), intent(in) :: mc
1185
1186#ifdef HAVE_MPI
1187 integer :: islave
1188#endif
1189
1190 push_sub(poisson_async_end)
1191
1192#ifdef HAVE_MPI
1193 if (multicomm_have_slaves(mc)) then
1194
1195 ! send the finish signal
1196 do islave = this%local_grp%rank, this%nslaves - 1, this%local_grp%size
1197 call mpi_send(m_one, 1, mpi_double_precision, islave, cmd_finish, this%intercomm)
1198 end do
1199
1200 end if
1201#endif
1202
1203 pop_sub(poisson_async_end)
1204
1205 end subroutine poisson_async_end
1206
1207 !-----------------------------------------------------------------
1208
1209 subroutine poisson_slave_work(this, namespace)
1210 type(poisson_t), intent(inout) :: this
1211 type(namespace_t), intent(in) :: namespace
1212
1213#ifdef HAVE_MPI
1214 real(real64), allocatable :: rho(:), pot(:)
1215 logical :: done
1216 type(mpi_status) :: status
1217 integer :: bcast_root
1218
1219 push_sub(poisson_slave_work)
1220 call profiling_in("SLAVE_WORK")
1221
1222 safe_allocate(rho(1:this%der%mesh%np))
1223 safe_allocate(pot(1:this%der%mesh%np))
1224 done = .false.
1225
1226 do while(.not. done)
1227
1228 call profiling_in("SLAVE_WAIT")
1229 call mpi_recv(rho(1), this%der%mesh%np, mpi_double_precision, mpi_any_source, mpi_any_tag, this%intercomm, status)
1230 call profiling_out("SLAVE_WAIT")
1231
1232 ! The tag of the message tells us what we have to do.
1233 select case (status%MPI_TAG)
1234
1235 case (cmd_finish)
1236 done = .true.
1238 case (cmd_poisson_solve)
1239 call dpoisson_solve(this, namespace, pot, rho)
1240
1241 call profiling_in("SLAVE_BROADCAST")
1242 bcast_root = mpi_proc_null
1243 if (this%root) bcast_root = mpi_root
1244 call mpi_bcast(pot(1), this%der%mesh%np, mpi_double_precision, bcast_root, this%intercomm)
1245 call profiling_out("SLAVE_BROADCAST")
1246
1247 end select
1248
1249 end do
1250
1251 safe_deallocate_a(pot)
1252 safe_deallocate_a(rho)
1253
1254 call profiling_out("SLAVE_WORK")
1255 pop_sub(poisson_slave_work)
1256#endif
1257 end subroutine poisson_slave_work
1258
1259 !----------------------------------------------------------------
1260
1261 logical pure function poisson_is_async(this) result(async)
1262 type(poisson_t), intent(in) :: this
1263
1264 async = (this%nslaves > 0)
1266 end function poisson_is_async
1267
1268 !----------------------------------------------------------------
1269
1270 subroutine poisson_build_kernel(this, namespace, space, coulb, qq, cam, singul)
1271 type(poisson_t), intent(in) :: this
1272 type(namespace_t), intent(in) :: namespace
1273 class(space_t), intent(in) :: space
1274 type(fourier_space_op_t), intent(inout) :: coulb
1275 real(real64), intent(in) :: qq(:)
1276 type(xc_cam_t), intent(in) :: cam
1277 real(real64), optional, intent(in) :: singul
1278
1279 logical :: reinit
1280
1281 push_sub(poisson_build_kernel)
1283 if (space%is_periodic()) then
1284 assert(ubound(qq, 1) >= space%periodic_dim)
1285 assert(this%method == poisson_fft)
1286 end if
1287
1288 if (cam%omega > m_epsilon) then
1289 if (this%method /= poisson_fft) then
1290 write(message(1),'(a)') "Poisson solver with range separation is only implemented with FFT."
1291 call messages_fatal(1, namespace=namespace)
1292 end if
1293 end if
1294
1295 !We only reinitialize the poisson solver if needed
1296 reinit = .false.
1297 if (allocated(coulb%qq)) then
1298 reinit = any(abs(coulb%qq(1:space%periodic_dim) - qq(1:space%periodic_dim)) > m_epsilon)
1299 end if
1300 reinit = reinit .or. (abs(coulb%mu - cam%omega) > m_epsilon .and. cam%omega > m_epsilon)
1301 reinit = reinit .or. (abs(coulb%alpha - cam%alpha) > m_epsilon .and. cam%alpha > m_epsilon)
1302 reinit = reinit .or. (abs(coulb%beta - cam%beta) > m_epsilon .and. cam%beta > m_epsilon)
1303
1304 if (reinit) then
1305 call profiling_in('POISSON_BUILD_KERNEL')
1306 !TODO: this should be a select case supporting other kernels.
1307 ! This means that we need an abstract object for kernels.
1308 select case (this%method)
1309 case (poisson_fft)
1310 ! Check that we are consistent: the Poisson solver supports must return 1 here
1311 assert(is_close(poisson_get_full_range_weight(this, cam), m_one))
1312 call fourier_space_op_end(coulb)
1313 call coulb%init(space, qq, cam, singul)
1314 call poisson_fft_get_kernel(namespace, space, this%cube, coulb, this%kernel, &
1315 this%poisson_soft_coulomb_param)
1316 case default
1317 call messages_not_implemented("poisson_build_kernel with other methods than FFT", namespace=namespace)
1318 end select
1319 call profiling_out('POISSON_BUILD_KERNEL')
1320 end if
1321
1322 pop_sub(poisson_build_kernel)
1323 end subroutine poisson_build_kernel
1324
1325 !----------------------------------------------------------------
1334 real(real64) function poisson_get_full_range_weight(this, cam) result(weight)
1335 type(poisson_t), intent(in) :: this
1336 type(xc_cam_t), intent(in) :: cam
1337
1338 select case (this%method)
1339 case (poisson_fft)
1340 weight = m_one
1341 case default
1342 if(cam%omega < m_epsilon) then
1343 weight = cam%alpha
1344 else if(cam%alpha > m_epsilon .and. cam%beta < m_epsilon) then
1345 weight = cam%alpha
1346 else if(cam%alpha < m_epsilon .and. cam%beta > m_epsilon) then
1347 weight = cam%beta
1348 else
1349 assert(.false.)
1350 end if
1351 end select
1353
1354#include "poisson_init_inc.F90"
1355#include "poisson_direct_inc.F90"
1356#include "poisson_direct_sm_inc.F90"
1357
1358#include "undef.F90"
1359#include "real.F90"
1360#include "poisson_inc.F90"
1361#include "undef.F90"
1362#include "complex.F90"
1363#include "poisson_inc.F90"
1364
1365end module poisson_oct_m
1366
1367!! Local Variables:
1368!! mode: f90
1369!! coding: utf-8
1370!! 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:1007
subroutine, public accel_kernel_start_call(this, file_name, kernel_name, flags)
Definition: accel.F90:1482
subroutine, public accel_finish()
Definition: accel.F90:1125
integer, parameter, public accel_mem_read_write
Definition: accel.F90:187
pure logical function, public accel_is_enabled()
Definition: accel.F90:404
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:2428
integer, parameter, public poisson_multigrid
Definition: poisson.F90:191
subroutine poisson_kernel_init(this, namespace, space, mc, stencil)
Definition: poisson.F90:1387
integer, parameter, public poisson_psolver
Definition: poisson.F90:191
subroutine, public dpoisson_solve_start(this, rho)
Definition: poisson.F90:2152
integer, parameter cmd_finish
Definition: poisson.F90:227
subroutine, public zpoisson_solve_finish(this, pot)
Definition: poisson.F90:2416
subroutine poisson_solve_direct(this, namespace, pot, rho)
Definition: poisson.F90:1598
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:2563
subroutine, public zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Definition: poisson.F90:912
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
Definition: poisson.F90:1125
subroutine, public poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
Definition: poisson.F90:958
subroutine, public poisson_async_init(this, mc)
Definition: poisson.F90:1238
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:2172
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:1231
subroutine, public poisson_slave_work(this, namespace)
Definition: poisson.F90:1266
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:1019
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:1283
subroutine, public dpoisson_solve_finish(this, pot)
Definition: poisson.F90:2160
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:2408
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:1250
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:1001
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:1347
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:2251
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:1274
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:992
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)