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 comm_oct_m
28 use cube_oct_m
30 use debug_oct_m
32 use fft_oct_m
34 use global_oct_m
35 use index_oct_m
36 use io_oct_m
38 use, intrinsic :: iso_fortran_env
41 use math_oct_m
42 use mesh_oct_m
46 use mpi_oct_m
49#ifdef HAVE_OPENMP
50 use omp_lib
51#endif
53 use parser_oct_m
64 use space_oct_m
67 use types_oct_m
68 use unit_oct_m
71
72 implicit none
73
74 private
75 public :: &
76 poisson_t, &
100
101 integer, public, parameter :: &
102 POISSON_DIRECT_SUM = -1, &
103 poisson_fft = 0, &
104 poisson_cg = 5, &
106 poisson_multigrid = 7, &
107 poisson_isf = 8, &
108 poisson_psolver = 10, &
109 poisson_no = -99, &
110 poisson_null = -999
111
112 type poisson_t
113 private
114 type(derivatives_t), pointer, public :: der
115 integer, public :: method = poisson_null
116 integer, public :: kernel
117 type(cube_t), public :: cube
118 type(mesh_cube_parallel_map_t), public :: mesh_cube_map
119 type(poisson_mg_solver_t) :: mg
120 type(poisson_fft_t), public :: fft_solver
121 real(real64), public :: poisson_soft_coulomb_param
122 logical :: all_nodes_default
123 type(poisson_corr_t) :: corrector
124 type(poisson_isf_t) :: isf_solver
125 type(poisson_psolver_t) :: psolver_solver
126 type(poisson_no_t) :: no_solver
127 integer :: nslaves
128 logical, public :: is_dressed = .false.
129 type(photon_mode_t), public :: photons
130#ifdef HAVE_MPI
131 type(MPI_Comm) :: intercomm
132 type(mpi_grp_t) :: local_grp
133 logical :: root
134#endif
135 end type poisson_t
136
137 integer, parameter :: &
138 CMD_FINISH = 1, &
140
141contains
142
143 !-----------------------------------------------------------------
144 subroutine poisson_init(this, namespace, space, der, mc, stencil, qtot, label, solver, verbose, force_serial, force_cmplx)
145 type(poisson_t), intent(inout) :: this
146 class(space_t), intent(in) :: space
147 type(namespace_t), intent(in) :: namespace
148 type(derivatives_t), target, intent(in) :: der
149 type(multicomm_t), intent(in) :: mc
150 type(stencil_t), intent(in) :: stencil
151 real(real64), optional, intent(in) :: qtot
152 character(len=*), optional, intent(in) :: label
153 integer, optional, intent(in) :: solver
154 logical, optional, intent(in) :: verbose
155 logical, optional, intent(in) :: force_serial
156 logical, optional, intent(in) :: force_cmplx
157
158 logical :: need_cube, isf_data_is_parallel
159 integer :: default_solver, default_kernel, box(space%dim), fft_type, fft_library
160 real(real64) :: fft_alpha
161 character(len=60) :: str
162
163 ! Make sure we do not try to initialize an already initialized solver
164 assert(this%method == poisson_null)
165
166 push_sub(poisson_init)
167
168 if (optional_default(verbose,.true.)) then
169 str = "Hartree"
170 if (present(label)) str = trim(label)
171 call messages_print_with_emphasis(msg=trim(str), namespace=namespace)
172 end if
173
174 this%nslaves = 0
175 this%der => der
176
177 !%Variable DressedOrbitals
178 !%Type logical
179 !%Default false
180 !%Section Hamiltonian::Poisson
181 !%Description
182 !% Allows for the calculation of coupled elecron-photon problems
183 !% by applying the dressed orbital approach. Details can be found in
184 !% https://arxiv.org/abs/1812.05562
185 !% At the moment, N electrons in d (<=3) spatial dimensions, coupled
186 !% to one photon mode can be described. The photon mode is included by
187 !% raising the orbital dimension to d+1 and changing the particle interaction
188 !% kernel and the local potential, where the former is included automatically,
189 !% but the latter needs to by added by hand as a user_defined_potential!
190 !% Coordinate 1-d: electron; coordinate d+1: photon.
191 !%End
192 call parse_variable(namespace, 'DressedOrbitals', .false., this%is_dressed)
193 call messages_print_var_value('DressedOrbitals', this%is_dressed, namespace=namespace)
194 if (this%is_dressed) then
195 assert(present(qtot))
196 call messages_experimental('Dressed Orbitals', namespace=namespace)
197 assert(qtot > m_zero)
198 call photon_mode_init(this%photons, namespace, der%dim-1)
199 call photon_mode_set_n_electrons(this%photons, qtot)
200 if(.not.allocated(this%photons%pol_dipole)) then
201 call photon_mode_compute_dipoles(this%photons, der%mesh)
202 end if
203 if (this%photons%nmodes > 1) then
204 call messages_not_implemented('DressedOrbitals for more than one photon mode', namespace=namespace)
205 end if
206 end if
208 this%all_nodes_default = .false.
209#ifdef HAVE_MPI
210 if (.not. optional_default(force_serial, .false.)) then
211 !%Variable ParallelizationPoissonAllNodes
212 !%Type logical
213 !%Default true
214 !%Section Execution::Parallelization
215 !%Description
216 !% When running in parallel, this variable selects whether the
217 !% Poisson solver should divide the work among all nodes or only
218 !% among the parallelization-in-domains groups.
219 !%End
221 call parse_variable(namespace, 'ParallelizationPoissonAllNodes', .true., this%all_nodes_default)
222 end if
223#endif
225 !%Variable PoissonSolver
226 !%Type integer
227 !%Section Hamiltonian::Poisson
228 !%Description
229 !% Defines which method to use to solve the Poisson equation. Some incompatibilities apply depending on
230 !% dimensionality, periodicity, etc.
231 !% For a comparison of the accuracy and performance of the methods in Octopus, see P Garcia-Risue&ntilde;o,
232 !% J Alberdi-Rodriguez <i>et al.</i>, <i>J. Comp. Chem.</i> <b>35</b>, 427-444 (2014)
233 !% or <a href=http://arxiv.org/abs/1211.2092>arXiV</a>.
234 !% Defaults:
235 !% <br> 1D and 2D: <tt>fft</tt>.
236 !% <br> 3D: <tt>cg_corrected</tt> if curvilinear, <tt>isf</tt> if not periodic, <tt>fft</tt> if periodic.
237 !% <br> Dressed orbitals: <tt>direct_sum</tt>.
238 !%Option NoPoisson -99
239 !% Do not use a Poisson solver at all.
240 !%Option direct_sum -1
241 !% Direct evaluation of the Hartree potential (only for finite systems).
242 !%Option fft 0
243 !% The Poisson equation is solved using FFTs. A cutoff technique
244 !% for the Poisson kernel is selected so the proper boundary
245 !% conditions are imposed according to the periodicity of the
246 !% system. This can be overridden by the <tt>PoissonFFTKernel</tt>
247 !% variable. To choose the FFT library use <tt>FFTLibrary</tt>
248 !%Option cg 5
249 !% Conjugate gradients (only for finite systems).
250 !%Option cg_corrected 6
251 !% Conjugate gradients, corrected for boundary conditions (only for finite systems).
252 !%Option multigrid 7
253 !% Multigrid method (only for finite systems).
254 !%Option isf 8
255 !% Interpolating Scaling Functions Poisson solver (only for finite systems).
256 !%Option psolver 10
257 !% Solver based on Interpolating Scaling Functions as implemented in the PSolver library.
258 !% Parallelization in k-points requires <tt>PoissonSolverPSolverParallelData</tt> = no.
259 !% Requires the PSolver external library.
260 !%End
261
262 default_solver = poisson_fft
263
264 if (space%dim == 3 .and. .not. space%is_periodic()) default_solver = poisson_isf
265
266#ifdef HAVE_CLFFT
267 ! this is disabled, since the difference between solvers are big
268 ! enough to cause problems with the tests.
269 ! if (accel_is_enabled()) default_solver = POISSON_FFT
270#endif
271#ifdef HAVE_CUDA
272 if(accel_is_enabled()) default_solver = poisson_fft
273#endif
274
275 if (space%dim > 3) default_solver = poisson_no ! Kernel for higher dimensions is not implemented.
276
277 if (der%mesh%use_curvilinear) then
278 select case (space%dim)
279 case (1)
280 default_solver = poisson_direct_sum
281 case (2)
282 default_solver = poisson_direct_sum
283 case (3)
284 default_solver = poisson_cg_corrected
285 end select
286 end if
287
288 if (this%is_dressed) default_solver = poisson_direct_sum
289
290 if (.not. present(solver)) then
291 call parse_variable(namespace, 'PoissonSolver', default_solver, this%method)
292 else
293 this%method = solver
294 end if
295 if (.not. varinfo_valid_option('PoissonSolver', this%method)) call messages_input_error(namespace, 'PoissonSolver')
296 if (optional_default(verbose, .true.)) then
297 select case (this%method)
298 case (poisson_direct_sum)
299 str = "direct sum"
300 case (poisson_fft)
301 str = "fast Fourier transform"
302 case (poisson_cg)
303 str = "conjugate gradients"
305 str = "conjugate gradients, corrected"
306 case (poisson_multigrid)
307 str = "multigrid"
308 case (poisson_isf)
309 str = "interpolating scaling functions"
310 case (poisson_psolver)
311 str = "interpolating scaling functions (from BigDFT)"
312 case (poisson_no)
313 str = "no Poisson solver - Hartree set to 0"
314 end select
315 write(message(1),'(a,a,a)') "The chosen Poisson solver is '", trim(str), "'"
316 call messages_info(1, namespace=namespace)
317 end if
318
319 if (space%dim > 3 .and. this%method /= poisson_no) then
320 call messages_input_error(namespace, 'PoissonSolver', 'Currently no Poisson solver is available for Dimensions > 3')
321 end if
322
323 if (this%method /= poisson_fft) then
324 this%kernel = poisson_fft_kernel_none
325 else
326
327 ! Documentation in cube.F90
328 call parse_variable(namespace, 'FFTLibrary', fftlib_fftw, fft_library)
329
330 !%Variable PoissonFFTKernel
331 !%Type integer
332 !%Section Hamiltonian::Poisson
333 !%Description
334 !% Defines which kernel is used to impose the correct boundary
335 !% conditions when using FFTs to solve the Poisson equation. The
336 !% default is selected depending on the dimensionality and
337 !% periodicity of the system:
338 !% <br>In 1D, <tt>spherical</tt> if finite, <tt>fft_nocut</tt> if periodic.
339 !% <br>In 2D, <tt>spherical</tt> if finite, <tt>cylindrical</tt> if 1D-periodic, <tt>fft_nocut</tt> if 2D-periodic.
340 !% <br>In 3D, <tt>spherical</tt> if finite, <tt>cylindrical</tt> if 1D-periodic, <tt>planar</tt> if 2D-periodic,
341 !% <tt>fft_nocut</tt> if 3D-periodic.
342 !% See C. A. Rozzi et al., <i>Phys. Rev. B</i> <b>73</b>, 205119 (2006) for 3D implementation and
343 !% A. Castro et al., <i>Phys. Rev. B</i> <b>80</b>, 033102 (2009) for 2D implementation.
344 !%Option spherical 0
345 !% FFTs using spherical cutoff (in 2D or 3D).
346 !%Option cylindrical 1
347 !% FFTs using cylindrical cutoff (in 2D or 3D).
348 !%Option planar 2
349 !% FFTs using planar cutoff (in 3D).
350 !%Option fft_nocut 3
351 !% FFTs without using a cutoff (for fully periodic systems).
352 !%Option multipole_correction 4
353 !% The boundary conditions are imposed by using a multipole expansion. Only appropriate for finite systems.
354 !% Further specification occurs with variables <tt>PoissonSolverBoundaries</tt> and <tt>PoissonSolverMaxMultipole</tt>.
355 !%End
356
357 select case (space%dim)
358 case (1)
359 if (.not. space%is_periodic()) then
360 default_kernel = poisson_fft_kernel_sph
361 else
362 default_kernel = poisson_fft_kernel_nocut
363 end if
364 case (2)
365 if (space%periodic_dim == 2) then
366 default_kernel = poisson_fft_kernel_nocut
367 else if (space%is_periodic()) then
368 default_kernel = space%periodic_dim
369 else
370 default_kernel = poisson_fft_kernel_sph
371 end if
372 case (3)
373 default_kernel = space%periodic_dim
374 end select
375
376 call parse_variable(namespace, 'PoissonFFTKernel', default_kernel, this%kernel)
377 if (.not. varinfo_valid_option('PoissonFFTKernel', this%kernel)) call messages_input_error(namespace, 'PoissonFFTKernel')
378
379 if (optional_default(verbose,.true.)) then
380 call messages_print_var_option("PoissonFFTKernel", this%kernel, namespace=namespace)
381 end if
382
383 ! the multipole correction kernel does not work on GPUs
384 if(this%kernel == poisson_fft_kernel_corrected .and. fft_default_lib == fftlib_accel) then
386 message(1) = 'PoissonFFTKernel=multipole_correction is not supported on GPUs'
387 message(2) = 'Using FFTW to compute the FFTs on the CPU'
388 call messages_info(2, namespace=namespace)
389 end if
390
391 end if
392
393 !We assume the developer knows what he is doing by providing the solver option
394 if (.not. present(solver)) then
395 if (space%is_periodic() .and. this%method == poisson_direct_sum) then
396 message(1) = 'A periodic system may not use the direct_sum Poisson solver.'
397 call messages_fatal(1, namespace=namespace)
398 end if
399
400 if (space%is_periodic() .and. this%method == poisson_cg_corrected) then
401 message(1) = 'A periodic system may not use the cg_corrected Poisson solver.'
402 call messages_fatal(1, namespace=namespace)
403 end if
404
405 if (space%is_periodic() .and. this%method == poisson_cg) then
406 message(1) = 'A periodic system may not use the cg Poisson solver.'
407 call messages_fatal(1, namespace=namespace)
408 end if
409
410 if (space%is_periodic() .and. this%method == poisson_multigrid) then
411 message(1) = 'A periodic system may not use the multigrid Poisson solver.'
412 call messages_fatal(1, namespace=namespace)
413 end if
414
415 select case (space%dim)
416 case (1)
417
418 select case (space%periodic_dim)
419 case (0)
420 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
421 message(1) = 'A finite 1D system may only use fft or direct_sum Poisson solvers.'
422 call messages_fatal(1, namespace=namespace)
423 end if
424 case (1)
425 if (this%method /= poisson_fft) then
426 message(1) = 'A periodic 1D system may only use the fft Poisson solver.'
427 call messages_fatal(1, namespace=namespace)
428 end if
429 end select
430
431 if (der%mesh%use_curvilinear .and. this%method /= poisson_direct_sum) then
432 message(1) = 'If curvilinear coordinates are used in 1D, then the only working'
433 message(2) = 'Poisson solver is direct_sum.'
434 call messages_fatal(2, namespace=namespace)
435 end if
436
437 case (2)
438
439 if ((this%method /= poisson_fft) .and. (this%method /= poisson_direct_sum)) then
440 message(1) = 'A 2D system may only use fft or direct_sum solvers.'
441 call messages_fatal(1, namespace=namespace)
442 end if
443
444 if (der%mesh%use_curvilinear .and. (this%method /= poisson_direct_sum)) then
445 message(1) = 'If curvilinear coordinates are used in 2D, then the only working'
446 message(2) = 'Poisson solver is direct_sum.'
447 call messages_fatal(2, namespace=namespace)
448 end if
449
450 case (3)
451
452 if (space%is_periodic() .and. this%method == poisson_isf) then
453 call messages_write('The ISF solver can only be used for finite systems.')
454 call messages_fatal()
455 end if
456
457 if (space%is_periodic() .and. this%method == poisson_fft .and. &
458 this%kernel /= space%periodic_dim .and. this%kernel >= 0 .and. this%kernel <= 3) then
459 write(message(1), '(a,i1,a)')'The system is periodic in ', space%periodic_dim ,' dimension(s),'
460 write(message(2), '(a,i1,a)')'but Poisson solver is set for ', this%kernel, ' dimensions.'
461 call messages_warning(2, namespace=namespace)
462 end if
463
464 if (space%is_periodic() .and. this%method == poisson_fft .and. this%kernel == poisson_fft_kernel_corrected) then
465 write(message(1), '(a,i1,a)')'PoissonFFTKernel = multipole_correction cannot be used for periodic systems.'
466 call messages_fatal(1, namespace=namespace)
467 end if
468
469 if (der%mesh%use_curvilinear .and. .not. any(this%method == [poisson_cg_corrected, poisson_multigrid])) then
470 message(1) = 'If curvilinear coordinates are used, then the only working'
471 message(2) = 'Poisson solver are cg_corrected and multigrid.'
472 call messages_fatal(2, namespace=namespace)
473 end if
474 if (der%mesh%use_curvilinear .and. this%method == poisson_multigrid .and. accel_is_enabled()) then
475 call messages_not_implemented('Multigrid Poisson solver with curvilinear coordinates on GPUs')
476 end if
477
478 select type (box => der%mesh%box)
479 type is (box_minimum_t)
480 if (this%method == poisson_cg_corrected) then
481 message(1) = 'When using the "minimum" box shape and the "cg_corrected"'
482 message(2) = 'Poisson solver, we have observed "sometimes" some non-'
483 message(3) = 'negligible error. You may want to check that the "fft" or "cg"'
484 message(4) = 'solver are providing, in your case, the same results.'
485 call messages_warning(4, namespace=namespace)
486 end if
487 end select
488
489 end select
490 end if
491
492 if (this%method == poisson_psolver) then
493#if !(defined HAVE_PSOLVER)
494 message(1) = "The PSolver Poisson solver cannot be used since the code was not compiled with the PSolver library."
495 call messages_fatal(1, namespace=namespace)
496#endif
497 end if
498
499 if (optional_default(verbose,.true.)) then
500 call messages_print_with_emphasis(namespace=namespace)
501 end if
502
503 ! Now that we know the method, we check if we need a cube and its dimentions
504 need_cube = .false.
505 fft_type = fft_real
506 if (optional_default(force_cmplx, .false.)) fft_type = fft_complex
507
508 if (this%method == poisson_isf .or. this%method == poisson_psolver) then
509 fft_type = fft_none
510 box(:) = der%mesh%idx%ll(:)
511 need_cube = .true.
512 end if
513
514 if (this%method == poisson_psolver .and. multicomm_have_slaves(mc)) then
515 call messages_not_implemented('Task parallelization with PSolver Poisson solver', namespace=namespace)
516 end if
517
519 ! Documentation in poisson_psolver.F90
520 call parse_variable(namespace, 'PoissonSolverPSolverParallelData', .true., isf_data_is_parallel)
521 if (this%method == poisson_psolver .and. isf_data_is_parallel) then
522 call messages_not_implemented("k-point parallelization with PSolver library and", namespace=namespace)
523 call messages_not_implemented("PoissonSolverPSolverParallelData = yes", namespace=namespace)
524 end if
525 if (this%method == poisson_fft .and. fft_library == fftlib_pfft) then
526 call messages_not_implemented("k-point parallelization with PFFT library for", namespace=namespace)
527 call messages_not_implemented("PFFT library for Poisson solver", namespace=namespace)
528 end if
529 end if
530
531 if (this%method == poisson_fft) then
532
533 need_cube = .true.
534
535 !%Variable DoubleFFTParameter
536 !%Type float
537 !%Default 2.0
538 !%Section Mesh::FFTs
539 !%Description
540 !% For solving the Poisson equation in Fourier space, and for applying the local potential
541 !% in Fourier space, an auxiliary cubic mesh is built. This mesh will be larger than
542 !% the circumscribed cube of the usual mesh by a factor <tt>DoubleFFTParameter</tt>. See
543 !% the section that refers to Poisson equation, and to the local potential for details
544 !% [the default value of two is typically good].
545 !%End
546 call parse_variable(namespace, 'DoubleFFTParameter', m_two, fft_alpha)
547 if (fft_alpha < m_one .or. fft_alpha > m_three) then
548 write(message(1), '(a,f12.5,a)') "Input: '", fft_alpha, &
549 "' is not a valid DoubleFFTParameter"
550 message(2) = '1.0 <= DoubleFFTParameter <= 3.0'
551 call messages_fatal(2, namespace=namespace)
552 end if
553
554 if (space%dim /= 3 .and. fft_library == fftlib_pfft) then
555 call messages_not_implemented('PFFT support for dimensionality other than 3', namespace=namespace)
556 end if
557
558 select case (space%dim)
559
560 case (1)
561 select case (this%kernel)
563 call mesh_double_box(space, der%mesh, fft_alpha, box)
565 box = der%mesh%idx%ll
566 end select
567
568 case (2)
569 select case (this%kernel)
571 call mesh_double_box(space, der%mesh, fft_alpha, box)
572 box(1:2) = maxval(box)
574 call mesh_double_box(space, der%mesh, fft_alpha, box)
576 box(:) = der%mesh%idx%ll(:)
577 end select
578
579 case (3)
580 select case (this%kernel)
582 call mesh_double_box(space, der%mesh, fft_alpha, box)
583 box(:) = maxval(box)
585 call mesh_double_box(space, der%mesh, fft_alpha, box)
586 box(2) = maxval(box(2:3)) ! max of finite directions
587 box(3) = maxval(box(2:3)) ! max of finite directions
589 box(:) = der%mesh%idx%ll(:)
591 call mesh_double_box(space, der%mesh, fft_alpha, box)
592 end select
593
594 end select
595
596 end if
597
598 ! Create the cube
599 if (need_cube) then
600 call cube_init(this%cube, box, namespace, space, der%mesh%spacing, &
601 der%mesh%coord_system, fft_type = fft_type, &
602 need_partition=.not.der%mesh%parallel_in_domains)
603 call cube_init_cube_map(this%cube, der%mesh)
604 if (this%cube%parallel_in_domains .and. this%method == poisson_fft) then
605 call mesh_cube_parallel_map_init(this%mesh_cube_map, der%mesh, this%cube)
606 end if
607 end if
608
609 if (this%is_dressed .and. .not. this%method == poisson_direct_sum) then
610 write(message(1), '(a)')'Dressed Orbital calculation currently only working with direct sum Poisson solver.'
611 call messages_fatal(1, namespace=namespace)
612 end if
613
614 call poisson_kernel_init(this, namespace, space, mc, stencil)
615
616 pop_sub(poisson_init)
617 end subroutine poisson_init
618
619 !-----------------------------------------------------------------
620 subroutine poisson_end(this)
621 type(poisson_t), intent(inout) :: this
622
623 logical :: has_cube
624
625 push_sub(poisson_end)
626
627 has_cube = .false.
628
629 select case (this%method)
630 case (poisson_fft)
631 call poisson_fft_end(this%fft_solver)
632 if (this%kernel == poisson_fft_kernel_corrected) call poisson_corrections_end(this%corrector)
633 has_cube = .true.
634
636 call poisson_cg_end()
637 call poisson_corrections_end(this%corrector)
638
639 case (poisson_multigrid)
640 call poisson_multigrid_end(this%mg)
641
642 case (poisson_isf)
643 call poisson_isf_end(this%isf_solver)
644 has_cube = .true.
645
646 case (poisson_psolver)
647 call poisson_psolver_end(this%psolver_solver)
648 has_cube = .true.
649
650 case (poisson_no)
651 call poisson_no_end(this%no_solver)
652
653 end select
654 this%method = poisson_null
655
656 if (has_cube) then
657 if (this%cube%parallel_in_domains) then
658 call mesh_cube_parallel_map_end(this%mesh_cube_map)
659 end if
660 call cube_end(this%cube)
661 end if
662
663 if (this%is_dressed) then
664 call photon_mode_end(this%photons)
665 end if
666 this%is_dressed = .false.
667
668 pop_sub(poisson_end)
669 end subroutine poisson_end
670
671 !-----------------------------------------------------------------
672
673 subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
674 type(poisson_t), intent(in) :: this
675 type(namespace_t), intent(in) :: namespace
676 complex(real64), intent(inout) :: pot(:)
677 complex(real64), intent(in) :: rho(:)
678 logical, optional, intent(in) :: all_nodes
679 type(fourier_space_op_t), optional, intent(in) :: kernel
680
681 real(real64), allocatable :: aux1(:), aux2(:)
682 type(derivatives_t), pointer :: der
683 logical :: all_nodes_value
684
685
686 der => this%der
687
689
690 call profiling_in('POISSON_RE_IM_SOLVE')
691
692 if (present(kernel)) then
693 assert(.not. any(abs(kernel%qq(:))>1e-8_real64))
694 end if
695
696 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
697
698 safe_allocate(aux1(1:der%mesh%np))
699 safe_allocate(aux2(1:der%mesh%np))
700 ! first the real part
701 aux1(1:der%mesh%np) = real(rho(1:der%mesh%np))
702 aux2(1:der%mesh%np) = real(pot(1:der%mesh%np))
703 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
704 pot(1:der%mesh%np) = aux2(1:der%mesh%np)
705
706 ! now the imaginary part
707 aux1(1:der%mesh%np) = aimag(rho(1:der%mesh%np))
708 aux2(1:der%mesh%np) = aimag(pot(1:der%mesh%np))
709 call dpoisson_solve(this, namespace, aux2, aux1, all_nodes=all_nodes_value, kernel=kernel)
710 pot(1:der%mesh%np) = pot(1:der%mesh%np) + m_zi*aux2(1:der%mesh%np)
711
712 safe_deallocate_a(aux1)
713 safe_deallocate_a(aux2)
714
715 call profiling_out('POISSON_RE_IM_SOLVE')
716
719
720 !-----------------------------------------------------------------
721
722 subroutine zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel)
723 type(poisson_t), intent(in) :: this
724 type(namespace_t), intent(in) :: namespace
725 complex(real64), contiguous, intent(inout) :: pot(:)
726 complex(real64), contiguous, intent(in) :: rho(:)
727 logical, optional, intent(in) :: all_nodes
728 type(fourier_space_op_t), optional, intent(in) :: kernel
729
730 logical :: all_nodes_value
731
732 push_sub(zpoisson_solve)
733
734 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
735
736 assert(ubound(pot, dim = 1) == this%der%mesh%np_part .or. ubound(pot, dim = 1) == this%der%mesh%np)
737 assert(ubound(rho, dim = 1) == this%der%mesh%np_part .or. ubound(rho, dim = 1) == this%der%mesh%np)
738
739 assert(this%method /= poisson_null)
740
741 if (this%method == poisson_fft .and. this%kernel /= poisson_fft_kernel_corrected &
742 .and. .not. this%is_dressed) then
743 !The default (real) Poisson solver is used for OEP and Sternheimer calls were we do not need
744 !a complex-to-xomplex FFT as these parts use the normal Coulomb potential
745 if (this%cube%fft%type == fft_complex) then
746 !We add the profiling here, as the other path uses dpoisson_solve
747 call profiling_in('ZPOISSON_SOLVE')
748 call zpoisson_fft_solve(this%fft_solver, this%der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
749 call profiling_out('ZPOISSON_SOLVE')
750 else
751 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel=kernel)
752 end if
753 else
754 call zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes_value, kernel = kernel)
755 end if
756
757 pop_sub(zpoisson_solve)
758 end subroutine zpoisson_solve
759
760
761 !-----------------------------------------------------------------
762
763 subroutine poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
764 type(poisson_t), intent(inout) :: this
765 type(namespace_t), intent(in) :: namespace
766 type(batch_t), intent(inout) :: potb
767 type(batch_t), intent(inout) :: rhob
768 logical, optional, intent(in) :: all_nodes
769 type(fourier_space_op_t), optional, intent(in) :: kernel
770
771 integer :: ii
772
773 push_sub(poisson_solve_batch)
774
775 assert(potb%nst_linear == rhob%nst_linear)
776 assert(potb%type() == rhob%type())
777
778 if (potb%type() == type_float) then
779 do ii = 1, potb%nst_linear
780 call dpoisson_solve(this, namespace, potb%dff_linear(:, ii), rhob%dff_linear(:, ii), all_nodes, kernel=kernel)
781 end do
782 else
783 do ii = 1, potb%nst_linear
784 call zpoisson_solve(this, namespace, potb%zff_linear(:, ii), rhob%zff_linear(:, ii), all_nodes, kernel=kernel)
785 end do
786 end if
787
788 pop_sub(poisson_solve_batch)
789 end subroutine poisson_solve_batch
790
791 !-----------------------------------------------------------------
792
798 subroutine dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel)
799 type(poisson_t), intent(in) :: this
800 type(namespace_t), intent(in) :: namespace
801 real(real64), contiguous, intent(inout) :: pot(:)
802 real(real64), contiguous, intent(in) :: rho(:)
806 logical, optional, intent(in) :: all_nodes
807 type(fourier_space_op_t), optional, intent(in) :: kernel
808
809 type(derivatives_t), pointer :: der
810 real(real64), allocatable :: rho_corrected(:), vh_correction(:)
811 logical :: all_nodes_value
812
813 call profiling_in('POISSON_SOLVE')
814 push_sub(dpoisson_solve)
816 der => this%der
817
818 assert(ubound(pot, dim = 1) == der%mesh%np_part .or. ubound(pot, dim = 1) == der%mesh%np)
819 assert(ubound(rho, dim = 1) == der%mesh%np_part .or. ubound(rho, dim = 1) == der%mesh%np)
820
821 ! Check optional argument and set to default if necessary.
822 all_nodes_value = optional_default(all_nodes, this%all_nodes_default)
823
824 assert(this%method /= poisson_null)
825
826 if (present(kernel)) then
827 assert(this%method == poisson_fft)
828 end if
829
830 select case (this%method)
831 case (poisson_direct_sum)
832 if ((this%is_dressed .and. this%der%dim - 1 > 3) .or. this%der%dim > 3) then
833 message(1) = "Direct sum Poisson solver only available for 1, 2, or 3 dimensions."
834 call messages_fatal(1, namespace=namespace)
835 end if
836 call poisson_solve_direct(this, namespace, pot, rho)
837
838 case (poisson_cg)
839 call poisson_cg1(namespace, der, this%corrector, pot, rho)
840
842 safe_allocate(rho_corrected(1:der%mesh%np))
843 safe_allocate(vh_correction(1:der%mesh%np_part))
844
845 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
846
847 pot(1:der%mesh%np) = pot(1:der%mesh%np) - vh_correction(1:der%mesh%np)
848 call poisson_cg2(namespace, der, pot, rho_corrected)
849 pot(1:der%mesh%np) = pot(1:der%mesh%np) + vh_correction(1:der%mesh%np)
850
851 safe_deallocate_a(rho_corrected)
852 safe_deallocate_a(vh_correction)
853
854 case (poisson_multigrid)
855 call poisson_multigrid_solver(this%mg, namespace, der, pot, rho)
857 case (poisson_fft)
858 if (this%kernel /= poisson_fft_kernel_corrected) then
859 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map, kernel=kernel)
860 else
861 safe_allocate(rho_corrected(1:der%mesh%np))
862 safe_allocate(vh_correction(1:der%mesh%np_part))
863
864 call correct_rho(this%corrector, der, rho, rho_corrected, vh_correction)
865 call dpoisson_fft_solve(this%fft_solver, der%mesh, this%cube, pot, rho_corrected, this%mesh_cube_map, &
866 average_to_zero = .true., kernel=kernel)
867
868 pot(1:der%mesh%np) = pot(1:der%mesh%np) + vh_correction(1:der%mesh%np)
869 safe_deallocate_a(rho_corrected)
870 safe_deallocate_a(vh_correction)
871 end if
872
873 case (poisson_isf)
874 call poisson_isf_solve(this%isf_solver, der%mesh, this%cube, pot, rho, all_nodes_value)
875
876
877 case (poisson_psolver)
878 if (this%psolver_solver%datacode == "G") then
879 ! Global version
880 call poisson_psolver_global_solve(this%psolver_solver, der%mesh, this%cube, pot, rho)
881 else ! "D" Distributed version
882 call poisson_psolver_parallel_solve(this%psolver_solver, der%mesh, this%cube, pot, rho, this%mesh_cube_map)
883 end if
884
885 case (poisson_no)
886 call poisson_no_solve(this%no_solver, der%mesh, pot, rho)
887 end select
888
889
890 ! Add extra terms for dressed interaction
891 if (this%is_dressed .and. this%method /= poisson_no) then
892 call photon_mode_add_poisson_terms(this%photons, der%mesh, rho, pot)
893 end if
894
895 pop_sub(dpoisson_solve)
896 call profiling_out('POISSON_SOLVE')
897 end subroutine dpoisson_solve
898
899 !-----------------------------------------------------------------
900 subroutine poisson_init_sm(this, namespace, space, main, der, sm, method, force_cmplx)
901 type(poisson_t), intent(inout) :: this
902 type(namespace_t), intent(in) :: namespace
903 class(space_t), intent(in) :: space
904 type(poisson_t), intent(in) :: main
905 type(derivatives_t), target, intent(in) :: der
906 type(submesh_t), intent(inout) :: sm
907 integer, optional, intent(in) :: method
908 logical, optional, intent(in) :: force_cmplx
909
910 integer :: default_solver, idir, iter, maxl
911 integer :: box(space%dim)
912 real(real64) :: qq(der%dim), threshold
913
914 if (this%method /= poisson_null) return ! already initialized
915
916 push_sub(poisson_init_sm)
917
918 this%is_dressed = .false.
919 !TODO: To be implemented as an option
920 this%all_nodes_default = .false.
921
922 this%nslaves = 0
923 this%der => der
924
925#ifdef HAVE_MPI
926 this%all_nodes_default = main%all_nodes_default
927#endif
928
929 default_solver = poisson_direct_sum
930 this%method = default_solver
931 if (present(method)) this%method = method
932
933 if (der%mesh%use_curvilinear) then
934 call messages_not_implemented("Submesh Poisson solver with curvilinear mesh", namespace=namespace)
935 end if
936
937 this%kernel = poisson_fft_kernel_none
938
939 select case (this%method)
940 case (poisson_direct_sum)
941 !Nothing to be done
942
943 case (poisson_isf)
944 !TODO: Add support for domain parrallelization
945 assert(.not. der%mesh%parallel_in_domains)
946 call submesh_get_cube_dim(sm, space, box)
947 call submesh_init_cube_map(sm, space)
948 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
949 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
950 call cube_init_cube_map(this%cube, sm%mesh)
951 call poisson_isf_init(this%isf_solver, namespace, der%mesh, this%cube, mpi_world%comm, init_world = this%all_nodes_default)
952
953 case (poisson_psolver)
954 !TODO: Add support for domain parrallelization
955 assert(.not. der%mesh%parallel_in_domains)
956 if (this%all_nodes_default) then
957 this%cube%mpi_grp = mpi_world
958 else
959 this%cube%mpi_grp = this%der%mesh%mpi_grp
960 end if
961 call submesh_get_cube_dim(sm, space, box)
962 call submesh_init_cube_map(sm, space)
963 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
964 fft_type = fft_none, need_partition=.not.der%mesh%parallel_in_domains)
965 call cube_init_cube_map(this%cube, sm%mesh)
966 qq = m_zero
967 call poisson_psolver_init(this%psolver_solver, namespace, space, this%cube, m_zero, qq, force_isolated=.true.)
968 call poisson_psolver_get_dims(this%psolver_solver, this%cube)
969 case (poisson_fft)
970 !Here we impose zero boundary conditions
971 this%kernel = poisson_fft_kernel_sph
972 !We need to parse this, in case this routine is called before poisson_init
973 call parse_variable(namespace, 'FFTLibrary', fftlib_fftw, fft_default_lib)
974
975 call submesh_get_cube_dim(sm, space, box)
976 call submesh_init_cube_map(sm, space)
977 !We double the size of the cell
978 !Maybe the factor of two should be controlled as a variable
979 do idir = 1, space%dim
980 box(idir) = nint(m_two * (box(idir) - 1)) + 1
981 end do
982 if (optional_default(force_cmplx, .false.)) then
983 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
984 fft_type = fft_complex, need_partition=.not.der%mesh%parallel_in_domains)
985 else
986 call cube_init(this%cube, box, namespace, space, sm%mesh%spacing, sm%mesh%coord_system, &
987 fft_type = fft_real, need_partition=.not.der%mesh%parallel_in_domains)
988 end if
989 call poisson_fft_init(this%fft_solver, namespace, space, this%cube, this%kernel)
990 case (poisson_cg)
991 call parse_variable(namespace, 'PoissonSolverMaxMultipole', 4, maxl)
992 write(message(1),'(a,i2)')'Info: Boundary conditions fixed up to L =', maxl
993 call messages_info(1, namespace=namespace)
994 call parse_variable(namespace, 'PoissonSolverMaxIter', 500, iter)
995 call parse_variable(namespace, 'PoissonSolverThreshold', 1.0e-6_real64, threshold)
996 call poisson_corrections_init(this%corrector, namespace, space, maxl, this%der%mesh)
997 call poisson_cg_init(threshold, iter)
998 end select
999
1000 pop_sub(poisson_init_sm)
1001 end subroutine poisson_init_sm
1002
1003 !-----------------------------------------------------------------
1010 subroutine poisson_test(this, space, mesh, latt, namespace, repetitions)
1011 type(poisson_t), intent(in) :: this
1012 class(space_t), intent(in) :: space
1013 class(mesh_t), intent(in) :: mesh
1014 type(lattice_vectors_t), intent(in) :: latt
1015 type(namespace_t), intent(in) :: namespace
1016 integer, intent(in) :: repetitions
1017
1018 real(real64), allocatable :: rho(:), vh(:), vh_exact(:), xx(:, :), xx_per(:)
1019 real(real64) :: alpha, beta, rr, delta, ralpha, hartree_nrg_num, &
1020 hartree_nrg_analyt, lcl_hartree_nrg
1021 real(real64) :: total_charge
1022 integer :: ip, ierr, iunit, nn, n_gaussians, itime, icell
1023 real(real64) :: threshold
1024 type(lattice_iterator_t) :: latt_iter
1025
1026 push_sub(poisson_test)
1027
1028 if (mesh%box%dim == 1) then
1029 call messages_not_implemented('Poisson test for 1D case', namespace=namespace)
1030 end if
1031
1032 !%Variable PoissonTestPeriodicThreshold
1033 !%Type float
1034 !%Default 1e-5
1035 !%Section Hamiltonian::Poisson
1036 !%Description
1037 !% This threshold determines the accuracy of the periodic copies of
1038 !% the Gaussian charge distribution that are taken into account when
1039 !% computing the analytical solution for periodic systems.
1040 !% Be aware that the default leads to good results for systems
1041 !% that are periodic in 1D - for 3D it is very costly because of the
1042 !% large number of copies needed.
1043 !%End
1044 call parse_variable(namespace, 'PoissonTestPeriodicThreshold', 1e-5_real64, threshold)
1045
1046 ! Use two gaussians with different sign
1047 n_gaussians = 2
1048
1049 safe_allocate( rho(1:mesh%np))
1050 safe_allocate( vh(1:mesh%np))
1051 safe_allocate(vh_exact(1:mesh%np))
1052 safe_allocate(xx(1:space%dim, 1:n_gaussians))
1053 safe_allocate(xx_per(1:space%dim))
1054
1055 rho = m_zero
1056 vh = m_zero
1057 vh_exact = m_zero
1058
1059 alpha = m_four*mesh%spacing(1)
1060 write(message(1),'(a,f14.6)') "Info: The alpha value is ", alpha
1061 write(message(2),'(a)') " Higher values of alpha lead to more physical densities and more reliable results."
1062 call messages_info(2, namespace=namespace)
1063 beta = m_one / (alpha**space%dim * sqrt(m_pi)**space%dim)
1064
1065 write(message(1), '(a)') 'Building the Gaussian distribution of charge...'
1066 call messages_info(1, namespace=namespace)
1067
1068 ! Set the centers of the Gaussians by hand
1069 xx(1, 1) = m_one
1070 xx(2, 1) = -m_half
1071 if (space%dim == 3) xx(3, 1) = m_two
1072 xx(1, 2) = -m_two
1073 xx(2, 2) = m_zero
1074 if (space%dim == 3) xx(3, 2) = -m_one
1075 xx = xx * alpha
1076
1077 ! Density as sum of Gaussians
1078 rho = m_zero
1079 do nn = 1, n_gaussians
1080 do ip = 1, mesh%np
1081 call mesh_r(mesh, ip, rr, origin = xx(:, nn))
1082 rho(ip) = rho(ip) + (-1)**nn * beta*exp(-(rr/alpha)**2)
1083 end do
1084 end do
1085
1086 total_charge = dmf_integrate(mesh, rho)
1087
1088 write(message(1), '(a,e23.16)') 'Total charge of the Gaussian distribution', total_charge
1089 call messages_info(1, namespace=namespace)
1090
1091 write(message(1), '(a)') 'Computing exact potential.'
1092 call messages_info(1, namespace=namespace)
1093
1094 ! This builds analytically its potential
1095 vh_exact = m_zero
1096 latt_iter = lattice_iterator_t(latt, m_one/threshold)
1097 do nn = 1, n_gaussians
1098 ! sum over all periodic copies for each Gaussian
1099 write(message(1), '(a,i2,a,i9,a)') 'Computing Gaussian ', nn, ' for ', latt_iter%n_cells, ' periodic copies.'
1100 call messages_info(1, namespace=namespace)
1101
1102 do icell = 1, latt_iter%n_cells
1103 xx_per = xx(:, nn) + latt_iter%get(icell)
1104 !$omp parallel do private(rr, ralpha)
1105 do ip = 1, mesh%np
1106 call mesh_r(mesh, ip, rr, origin=xx_per)
1107 select case (space%dim)
1108 case (3)
1109 if (rr > r_small) then
1110 vh_exact(ip) = vh_exact(ip) + (-1)**nn * loct_erf(rr/alpha)/rr
1111 else
1112 vh_exact(ip) = vh_exact(ip) + (-1)**nn * (m_two/sqrt(m_pi))/alpha
1113 end if
1114 case (2)
1115 ralpha = rr**2/(m_two*alpha**2)
1116 if (ralpha < 100.0_real64) then
1117 vh_exact(ip) = vh_exact(ip) + (-1)**nn * beta * (m_pi)**(m_three*m_half) * alpha * exp(-rr**2/(m_two*alpha**2)) * &
1118 loct_bessel_in(0, rr**2/(m_two*alpha**2))
1119 else
1120 vh_exact(ip) = vh_exact(ip) + (-1)**nn * beta * (m_pi)**(m_three*m_half) * alpha * &
1121 (m_one/sqrt(m_two*m_pi*ralpha))
1122 end if
1123 end select
1124 end do
1125 end do
1126 end do
1127
1128 ! This calculates the numerical potential
1129 do itime = 1, repetitions
1130 call dpoisson_solve(this, namespace, vh, rho)
1131 end do
1132
1133 ! Output results
1134 iunit = io_open("hartree_results", namespace, action='write')
1135 delta = dmf_nrm2(mesh, vh-vh_exact)
1136 write(iunit, '(a,e23.16)') 'Hartree test (abs.) = ', delta
1137 delta = delta/dmf_nrm2(mesh, vh_exact)
1138 write(iunit, '(a,e23.16)') 'Hartree test (rel.) = ', delta
1139
1140 ! Calculate the numerical Hartree energy (serially)
1141 lcl_hartree_nrg = m_zero
1142 do ip = 1, mesh%np
1143 lcl_hartree_nrg = lcl_hartree_nrg + rho(ip) * vh(ip)
1144 end do
1145 lcl_hartree_nrg = lcl_hartree_nrg * mesh%spacing(1) * mesh%spacing(2) * mesh%spacing(3)/m_two
1146#ifdef HAVE_MPI
1147 call mpi_reduce(lcl_hartree_nrg, hartree_nrg_num, 1, &
1148 mpi_double_precision, mpi_sum, 0, mpi_comm_world, mpi_err)
1149 if (mpi_err /= 0) then
1150 write(message(1),'(a)') "MPI error in MPI_Reduce; subroutine poisson_test of file poisson.F90"
1151 call messages_warning(1, namespace=namespace)
1152 end if
1153#else
1154 hartree_nrg_num = lcl_hartree_nrg
1155#endif
1156
1157 ! Calculate the analytical Hartree energy (serially, discrete - not exactly exact)
1158 lcl_hartree_nrg = m_zero
1159 do ip = 1, mesh%np
1160 lcl_hartree_nrg = lcl_hartree_nrg + rho(ip) * vh_exact(ip)
1161 end do
1162 lcl_hartree_nrg = lcl_hartree_nrg * mesh%spacing(1) * mesh%spacing(2) * mesh%spacing(3) / m_two
1163#ifdef HAVE_MPI
1164 call mpi_reduce(lcl_hartree_nrg, hartree_nrg_analyt, 1, &
1165 mpi_double_precision, mpi_sum, 0, mpi_comm_world, mpi_err)
1166 if (mpi_err /= 0) then
1167 write(message(1),'(a)') "MPI error in MPI_Reduce; subroutine poisson_test of file poisson.F90"
1168 call messages_warning(1, namespace=namespace)
1169 end if
1170#else
1171 hartree_nrg_analyt = lcl_hartree_nrg
1172#endif
1173
1174 write(iunit, '(a)')
1175
1176 if (mpi_world%rank == 0) then
1177 write(iunit,'(a,e23.16)') 'Hartree Energy (numerical) =', hartree_nrg_num, 'Hartree Energy (analytical) =',hartree_nrg_analyt
1178 end if
1179
1180 call io_close(iunit)
1181
1182 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_rho", namespace, space, &
1183 mesh, rho, unit_one, ierr)
1184 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_exact", namespace, space, &
1185 mesh, vh_exact, unit_one, ierr)
1186 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_numerical", namespace, space, &
1187 mesh, vh, unit_one, ierr)
1188 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_rho", namespace, space, &
1189 mesh, rho, unit_one, ierr)
1190 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_exact", namespace, space, &
1191 mesh, vh_exact, unit_one, ierr)
1192 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_numerical", namespace, space, &
1193 mesh, vh, unit_one, ierr)
1194 ! not dimensionless, but no need for unit conversion for a test routine
1195
1196 safe_deallocate_a(rho)
1197 safe_deallocate_a(vh)
1198 safe_deallocate_a(vh_exact)
1199 safe_deallocate_a(xx)
1200
1201 pop_sub(poisson_test)
1202 end subroutine poisson_test
1203
1204 ! -----------------------------------------------------------------
1205
1206 logical pure function poisson_solver_is_iterative(this) result(iterative)
1207 type(poisson_t), intent(in) :: this
1208
1209 iterative = this%method == poisson_cg .or. this%method == poisson_cg_corrected
1210 end function poisson_solver_is_iterative
1211
1212 ! -----------------------------------------------------------------
1213
1214 logical pure function poisson_is_multigrid(this) result(is_multigrid)
1215 type(poisson_t), intent(in) :: this
1216
1217 is_multigrid = (this%method == poisson_multigrid)
1218
1219 end function poisson_is_multigrid
1220
1221 ! -----------------------------------------------------------------
1222
1223 logical pure function poisson_solver_has_free_bc(this) result(free_bc)
1224 type(poisson_t), intent(in) :: this
1225
1226 free_bc = .true.
1227
1228 if (this%method == poisson_fft .and. &
1229 this%kernel /= poisson_fft_kernel_sph .and. this%kernel /= poisson_fft_kernel_corrected) then
1230 free_bc = .false.
1231 end if
1232
1233 end function poisson_solver_has_free_bc
1234
1235 !-----------------------------------------------------------------
1236
1237 integer pure function poisson_get_solver(this) result (solver)
1238 type(poisson_t), intent(in) :: this
1239
1240 solver = this%method
1241 end function poisson_get_solver
1242
1243 !-----------------------------------------------------------------
1244
1245 subroutine poisson_async_init(this, mc)
1246 type(poisson_t), intent(inout) :: this
1247 type(multicomm_t), intent(in) :: mc
1248
1249 push_sub(poisson_async_init)
1250
1251#ifdef HAVE_MPI
1252 if (multicomm_have_slaves(mc)) then
1253
1254 call mpi_grp_init(this%local_grp, mc%group_comm(p_strategy_states))
1255
1256 this%root = (this%local_grp%rank == 0)
1257
1258 this%intercomm = mc%slave_intercomm
1259 call mpi_comm_remote_size(this%intercomm, this%nslaves, mpi_err)
1260
1261 end if
1262#endif
1263
1264 pop_sub(poisson_async_init)
1265
1266 end subroutine poisson_async_init
1267
1268 !-----------------------------------------------------------------
1269
1270 subroutine poisson_async_end(this, mc)
1271 type(poisson_t), intent(inout) :: this
1272 type(multicomm_t), intent(in) :: mc
1273
1274#ifdef HAVE_MPI
1275 integer :: islave
1276#endif
1277
1278 push_sub(poisson_async_end)
1279
1280#ifdef HAVE_MPI
1281 if (multicomm_have_slaves(mc)) then
1282
1283 ! send the finish signal
1284 do islave = this%local_grp%rank, this%nslaves - 1, this%local_grp%size
1285 call mpi_send(m_one, 1, mpi_double_precision, islave, cmd_finish, this%intercomm, mpi_err)
1286 end do
1287
1288 end if
1289#endif
1290
1291 pop_sub(poisson_async_end)
1292
1293 end subroutine poisson_async_end
1294
1295 !-----------------------------------------------------------------
1296
1297 subroutine poisson_slave_work(this, namespace)
1298 type(poisson_t), intent(inout) :: this
1299 type(namespace_t), intent(in) :: namespace
1300
1301#ifdef HAVE_MPI
1302 real(real64), allocatable :: rho(:), pot(:)
1303 logical :: done
1304 type(mpi_status) :: status
1305 integer :: bcast_root
1306
1308 call profiling_in("SLAVE_WORK")
1309
1310 safe_allocate(rho(1:this%der%mesh%np))
1311 safe_allocate(pot(1:this%der%mesh%np))
1312 done = .false.
1313
1314 do while(.not. done)
1315
1316 call profiling_in("SLAVE_WAIT")
1317 call mpi_recv(rho(1), this%der%mesh%np, mpi_double_precision, mpi_any_source, mpi_any_tag, this%intercomm, status, mpi_err)
1318 call profiling_out("SLAVE_WAIT")
1319
1320 ! The tag of the message tells us what we have to do.
1321 select case (status%MPI_TAG)
1322
1323 case (cmd_finish)
1324 done = .true.
1325
1326 case (cmd_poisson_solve)
1327 call dpoisson_solve(this, namespace, pot, rho)
1328
1329 call profiling_in("SLAVE_BROADCAST")
1330 bcast_root = mpi_proc_null
1331 if (this%root) bcast_root = mpi_root
1332 call mpi_bcast(pot(1), this%der%mesh%np, mpi_double_precision, bcast_root, this%intercomm, mpi_err)
1333 call profiling_out("SLAVE_BROADCAST")
1334
1335 end select
1336
1337 end do
1339 safe_deallocate_a(pot)
1340 safe_deallocate_a(rho)
1341
1342 call profiling_out("SLAVE_WORK")
1343 pop_sub(poisson_slave_work)
1344#endif
1345 end subroutine poisson_slave_work
1346
1347 !----------------------------------------------------------------
1348
1349 logical pure function poisson_is_async(this) result(async)
1350 type(poisson_t), intent(in) :: this
1351
1352 async = (this%nslaves > 0)
1353
1354 end function poisson_is_async
1355
1356 !----------------------------------------------------------------
1357
1358 subroutine poisson_build_kernel(this, namespace, space, coulb, qq, alpha, beta, mu, singul)
1359 type(poisson_t), intent(in) :: this
1360 type(namespace_t), intent(in) :: namespace
1361 class(space_t), intent(in) :: space
1362 type(fourier_space_op_t), intent(inout) :: coulb
1363 real(real64), intent(in) :: qq(:)
1364 real(real64), intent(in) :: alpha, beta, mu
1365 real(real64), optional, intent(in) :: singul
1366
1367 real(real64), parameter :: vanishing_q = 1.0e-5_real64
1368 logical :: reinit
1369
1370 push_sub(poisson_build_kernel)
1371
1372 if (space%is_periodic()) then
1373 assert(ubound(qq, 1) >= space%periodic_dim)
1374 assert(this%method == poisson_fft)
1375 end if
1376
1377 if (mu > m_epsilon) then
1378 if (this%method /= poisson_fft) then
1379 write(message(1),'(a)') "Poisson solver with range separation is only implemented with FFT."
1380 call messages_fatal(1, namespace=namespace)
1381 end if
1382 end if
1383
1384 !We only reinitialize the poisson solver if needed
1385 reinit = .false.
1386 if (allocated(coulb%qq)) then
1387 reinit = any(abs(coulb%qq(1:space%periodic_dim) - qq(1:space%periodic_dim)) > m_epsilon)
1388 end if
1389 reinit = reinit .or. (abs(coulb%mu-mu) > m_epsilon .and. mu > m_epsilon)
1390 reinit = reinit .or. (abs(coulb%alpha-alpha) > m_epsilon .and. alpha > m_epsilon)
1391 reinit = reinit .or. (abs(coulb%beta-beta) > m_epsilon .and. beta > m_epsilon)
1392
1393
1394 if (reinit) then
1395 !TODO: this should be a select case supporting other kernels.
1396 ! This means that we need an abstract object for kernels.
1397 select case (this%method)
1398 case (poisson_fft)
1399 ! Check that we are consistent: the Poisson solver supports must return 1 here
1400 assert(is_close(poisson_get_full_range_weight(this, alpha, beta, mu), m_one))
1401
1402 call fourier_space_op_end(coulb)
1403
1404 safe_allocate(coulb%qq(1:space%dim))
1405 coulb%qq(1:space%periodic_dim) = qq(1:space%periodic_dim)
1406 coulb%qq(space%periodic_dim+1:space%dim) = vanishing_q
1407 !We must define the singularity if we specify a q vector and we do not use the short-range Coulomb potential
1408 coulb%singularity = optional_default(singul, m_zero)
1409 coulb%mu = mu
1410 coulb%alpha = alpha
1411 coulb%beta = beta
1412 call poisson_fft_get_kernel(namespace, space, this%cube, coulb, this%kernel, &
1413 this%poisson_soft_coulomb_param)
1414 case default
1415 call messages_not_implemented("poisson_build_kernel with other methods than FFT", namespace=namespace)
1416 end select
1417 end if
1418
1419 pop_sub(poisson_build_kernel)
1420 end subroutine poisson_build_kernel
1421
1422 !----------------------------------------------------------------
1431 real(real64) function poisson_get_full_range_weight(this, alpha, beta, mu) result(weight)
1432 type(poisson_t), intent(in) :: this
1433 real(real64), intent(in) :: alpha, beta, mu
1434
1435 select case (this%method)
1436 case (poisson_fft)
1437 weight = m_one
1438 case default
1439 if(mu < m_epsilon) then
1440 weight = alpha
1441 else if(alpha > m_epsilon .and. beta < m_epsilon) then
1442 weight = alpha
1443 else if(alpha < m_epsilon .and. beta > m_epsilon) then
1444 weight = beta
1445 else
1446 assert(.false.)
1447 end if
1448 end select
1450
1451#include "poisson_init_inc.F90"
1452#include "poisson_direct_inc.F90"
1453#include "poisson_direct_sm_inc.F90"
1454
1455#include "undef.F90"
1456#include "real.F90"
1457#include "poisson_inc.F90"
1458#include "undef.F90"
1459#include "complex.F90"
1460#include "poisson_inc.F90"
1461
1462end module poisson_oct_m
1463
1464!! Local Variables:
1465!! mode: f90
1466!! coding: utf-8
1467!! End:
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:180
double exp(double __x) __attribute__((__nothrow__
pure logical function, public accel_is_enabled()
Definition: accel.F90:400
This module implements batches of mesh functions.
Definition: batch.F90:133
This module handles the calculation mode.
integer, parameter, public p_strategy_kpoints
parallelization in k-points
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)
Definition: cube.F90:202
subroutine, public cube_end(cube)
Definition: cube.F90:378
subroutine, public cube_init_cube_map(cube, mesh)
Definition: cube.F90:823
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:118
integer, parameter, public fft_none
global constants
Definition: fft.F90:177
integer, public fft_default_lib
Definition: fft.F90:258
integer, parameter, public fftlib_accel
Definition: fft.F90:182
integer, parameter, public fft_real
Definition: fft.F90:177
integer, parameter, public fft_complex
Definition: fft.F90:177
integer, parameter, public fftlib_pfft
Definition: fft.F90:182
integer, parameter, public fftlib_fftw
Definition: fft.F90:182
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public r_small
Definition: global.F90:179
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_four
Definition: global.F90:191
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public m_one
Definition: global.F90:188
real(real64), parameter, public m_three
Definition: global.F90:190
This module implements the index, used for the mesh points.
Definition: index.F90:122
subroutine, public dio_function_output(how, dir, fname, namespace, space, mesh, ff, unit, ierr, pos, atoms, grp, root)
Top-level IO routine for functions defined on the mesh.
integer(int64) function, public io_function_fill_how(where)
Use this function to quickly plot functions for debugging purposes: call dio_function_output(io_funct...
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
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.
real(real64) function, public dmf_integrate(mesh, ff, mask, reduce)
Integrate a function on the mesh.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public mesh_double_box(space, mesh, alpha, db)
finds the dimension of a box doubled in the non-periodic dimensions
Definition: mesh.F90:279
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:336
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1125
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:543
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:266
integer, public mpi_err
used to store return values of mpi calls
Definition: mpi.F90:269
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
logical pure function, public multicomm_strategy_is_parallel(mc, level)
Definition: multicomm.F90:927
logical pure function, public multicomm_have_slaves(this)
Definition: multicomm.F90:1143
Some general things and nomenclature:
Definition: par_vec.F90:171
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:136
subroutine, public poisson_cg2(namespace, der, pot, rho)
Definition: poisson_cg.F90:211
subroutine, public poisson_cg1(namespace, der, corrector, pot, rho)
Definition: poisson_cg.F90:162
subroutine, public poisson_cg_init(thr, itr)
Definition: poisson_cg.F90:144
subroutine, public poisson_cg_end
Definition: poisson_cg.F90:156
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:163
subroutine, public poisson_no_end(this)
Definition: poisson_no.F90:151
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:2542
integer, parameter, public poisson_multigrid
Definition: poisson.F90:194
subroutine poisson_kernel_init(this, namespace, space, mc, stencil)
Definition: poisson.F90:1565
integer, parameter, public poisson_psolver
Definition: poisson.F90:194
subroutine, public dpoisson_solve_start(this, rho)
Definition: poisson.F90:2311
integer, parameter cmd_finish
Definition: poisson.F90:230
subroutine, public zpoisson_solve_finish(this, pot)
Definition: poisson.F90:2519
subroutine poisson_solve_direct(this, namespace, pot, rho)
Definition: poisson.F90:1769
logical pure function, public poisson_solver_is_iterative(this)
Definition: poisson.F90:1300
integer, parameter, public poisson_fft
Definition: poisson.F90:194
logical pure function, public poisson_is_multigrid(this)
Definition: poisson.F90:1308
subroutine, public poisson_solve_batch(this, namespace, potb, rhob, all_nodes, kernel)
Definition: poisson.F90:857
subroutine, public zpoisson_solve(this, namespace, pot, rho, all_nodes, kernel)
Definition: poisson.F90:816
subroutine, public poisson_async_init(this, mc)
Definition: poisson.F90:1339
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:2357
subroutine zpoisson_solve_real_and_imag_separately(this, namespace, pot, rho, all_nodes, kernel)
Definition: poisson.F90:767
real(real64) function, public poisson_get_full_range_weight(this, alpha, beta, mu)
Most Poisson solvers do not implement Coulomb attenuated potentials, and can only be used for global ...
Definition: poisson.F90:1525
subroutine, public poisson_build_kernel(this, namespace, space, coulb, qq, alpha, beta, mu, singul)
Definition: poisson.F90:1452
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, method, force_cmplx)
Definition: poisson.F90:994
subroutine, public poisson_slave_work(this, namespace)
Definition: poisson.F90:1391
integer, parameter cmd_poisson_solve
Definition: poisson.F90:230
integer, parameter, public poisson_cg
Definition: poisson.F90:194
logical pure function, public poisson_solver_has_free_bc(this)
Definition: poisson.F90:1317
subroutine, public dpoisson_solve_finish(this, pot)
Definition: poisson.F90:2334
subroutine, public poisson_init(this, namespace, space, der, mc, stencil, qtot, label, solver, verbose, force_serial, force_cmplx)
Definition: poisson.F90:238
subroutine, public zpoisson_solve_start(this, rho)
Definition: poisson.F90:2496
subroutine, public poisson_async_end(this, mc)
Definition: poisson.F90:1364
integer, parameter, public poisson_cg_corrected
Definition: poisson.F90:194
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:892
integer pure function, public poisson_get_solver(this)
Definition: poisson.F90:1331
integer, parameter, public poisson_isf
Definition: poisson.F90:194
integer, parameter, public poisson_null
Definition: poisson.F90:194
subroutine, public poisson_test(this, space, mesh, latt, namespace, repetitions)
This routine checks the Hartree solver selected in the input file by calculating numerically and anal...
Definition: poisson.F90:1104
integer, parameter, public poisson_no
Definition: poisson.F90:194
logical pure function, public poisson_is_async(this)
Definition: poisson.F90:1443
subroutine, public poisson_end(this)
Definition: poisson.F90:714
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:623
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:552
This module defines stencils used in Octopus.
Definition: stencil.F90:135
subroutine, public submesh_init_cube_map(sm, space)
Definition: submesh.F90:1004
subroutine, public submesh_get_cube_dim(sm, space, db)
finds the dimension of a box containing the submesh
Definition: submesh.F90:973
type(type_t), public type_float
Definition: types.F90:133
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
This module defines the unit system, used for input and output.
type(unit_t), public unit_one
some special units required for particular quantities
Class defining batches of mesh functions.
Definition: batch.F90:159
Class implementing a box that is a union of spheres. We do this in a specific class instead of using ...
class representing derivatives
The following class implements a lattice iterator. It allows one to loop over all cells that are with...
Describes mesh distribution to nodes.
Definition: mesh.F90:186
A submesh is a type of mesh, used for the projectors in the pseudopotentials It contains points on a ...
Definition: submesh.F90:177
int true(void)