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