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