Octopus
poisson_corrections.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
22 use debug_oct_m
24 use global_oct_m
25 use iso_c_binding
28 use math_oct_m
30 use mesh_oct_m
34 use parser_oct_m
36 use space_oct_m
37
38 implicit none
39
40 private
41 public :: &
51
52 real(real64), parameter :: alpha_ = m_five
53
55 private
56 integer :: method
57 integer :: maxl
58 real(real64), allocatable :: phi(:, :)
59 real(real64), allocatable :: aux(:, :)
60 real(real64), allocatable :: gaussian(:)
61 end type poisson_corr_t
62
63 type(derivatives_t), pointer :: der_pointer
64 type(mesh_t), pointer :: mesh_pointer
65
66 integer, parameter :: &
67 CORR_MULTIPOLE = 1, &
68 corr_exact = 3
69
70contains
71
72 ! ---------------------------------------------------------
73 subroutine poisson_corrections_init(this, namespace, space, ml, mesh)
74 type(poisson_corr_t), intent(out) :: this
75 type(namespace_t), intent(in) :: namespace
76 class(space_t), intent(in) :: space
77 integer, intent(in) :: ml
78 type(mesh_t), intent(in) :: mesh
79
80 real(real64) :: alpha, gamma, ylm, rr, xx(space%dim)
81 integer :: ip, ll, add_lm, lldfac, jj, mm
82
84
85 assert(space%dim == 3)
86
87 if (space%is_periodic()) then
88 call messages_not_implemented("Poisson boundary corrections for periodic systems", namespace=namespace)
89 end if
90
91 !%Variable PoissonSolverBoundaries
92 !%Type integer
93 !%Section Hamiltonian::Poisson
94 !%Default multipole
95 !%Description
96 !% For finite systems, some Poisson solvers (<tt>multigrid</tt>,
97 !% <tt>cg_corrected</tt>, and <tt>fft</tt> with <tt>PoissonFFTKernel = multipole_correction</tt>)
98 !% require the calculation of the
99 !% boundary conditions with an auxiliary method. This variable selects that method.
100 !%Option multipole 1
101 !% A multipole expansion of the density is used to approximate the potential on the boundaries.
102 !%Option exact 3
103 !% An exact integration of the Poisson equation is done over the boundaries. This option is
104 !% experimental, and not implemented for domain parallelization.
105 !%End
106 call parse_variable(namespace, 'PoissonSolverBoundaries', corr_multipole, this%method)
107
108 select case (this%method)
109 case (corr_multipole)
110 this%maxl = ml
111
112 add_lm = 0
113 do ll = 0, this%maxl
114 do mm = -ll, ll
115 add_lm = add_lm + 1
116 end do
117 end do
118
119 safe_allocate(this%phi(1:mesh%np, 1:add_lm))
120 safe_allocate(this%aux(1:mesh%np, 1:add_lm))
121 safe_allocate(this%gaussian(1:mesh%np))
122
123 alpha = alpha_ * mesh%spacing(1)
124 do ip = 1, mesh%np
125 call mesh_r(mesh, ip, rr, coords = xx)
126 this%gaussian(ip) = exp(-(rr/alpha)**2)
127 add_lm = 1
128 do ll = 0, this%maxl
129 lldfac = 1
130 do jj = 1, 2*ll+1, 2
131 lldfac = lldfac * jj
132 end do
133 gamma = sqrt(m_pi)*2**(ll+3) / lldfac
134 do mm = -ll, ll
135 call ylmr_real(xx, ll, mm, ylm)
136 if (rr > m_epsilon) then
137 this%phi(ip, add_lm) = gamma*isubl(ll, rr/alpha)*ylm/rr**(ll+1)
138 this%aux(ip, add_lm) = rr**ll*ylm
139 else
140 this%phi(ip, add_lm) = gamma*ylm / alpha
141 if (ll == 0) then
142 this%aux(ip, add_lm) = ylm
143 else
144 this%aux(ip, add_lm) = m_zero
145 end if
146 end if
147 add_lm = add_lm + 1
148 end do
149 end do
150 end do
153 call messages_experimental('Exact Poisson solver boundaries', namespace=namespace)
154 if (mesh%parallel_in_domains) call messages_not_implemented('Exact Poisson solver boundaries with domain parallelization')
156 end select
157
160 contains
162 ! ---------------------------------------------------------
163 real(real64) function isubl( ll, xx)
164 integer, intent(in) :: ll
165 real(real64), intent(in) :: xx
166
167 ! no push_sub, called too frequently
169
170 end function isubl
171
172 end subroutine poisson_corrections_init
173
174
175 ! ---------------------------------------------------------
176 subroutine poisson_corrections_end(this)
177 type(poisson_corr_t), intent(inout) :: this
178
180
181 select case (this%method)
182 case (corr_multipole)
183 safe_deallocate_a(this%phi)
184 safe_deallocate_a(this%aux)
185 safe_deallocate_a(this%gaussian)
186 case (corr_exact)
187 end select
188
190 end subroutine poisson_corrections_end
191
192
193 ! ---------------------------------------------------------
194 subroutine correct_rho(this, der, rho, rho_corrected, vh_correction)
195 type(poisson_corr_t), intent(in) :: this
196 type(derivatives_t), intent(in) :: der
197 real(real64), contiguous, intent(in) :: rho(:)
198 real(real64), contiguous, intent(out) :: rho_corrected(:)
199 real(real64), contiguous, intent(out) :: vh_correction(:)
200
201 integer :: ip, add_lm, ll, mm, lldfac, jj, ip2
202 real(real64) :: alpha, vv, rr
203 real(real64), allocatable :: mult(:)
204 real(real64), allocatable :: betal(:)
205
206 push_sub(correct_rho)
207 call profiling_in("POISSON_CORRECT")
208
209 assert(ubound(vh_correction, dim = 1) == der%mesh%np_part)
210
211 select case (this%method)
212 case (corr_multipole)
213
214 safe_allocate(mult(1:(this%maxl+1)**2))
215 call get_multipoles(this, der%mesh, rho, this%maxl, mult)
216
217 alpha = alpha_ * der%mesh%spacing(1)
218
219 safe_allocate(betal(1:(this%maxl+1)**2))
220 add_lm = 1
221 do ll = 0, this%maxl
222 do mm = -ll, ll
223 lldfac = 1
224 do jj = 1, 2*ll+1, 2
225 lldfac = lldfac*jj
226 end do
227 betal(add_lm) = (2**(ll + 2)) / (alpha**(2*ll+3) * sqrt(m_pi) * lldfac)
228 add_lm = add_lm + 1
229 end do
230 end do
231
232 call lalg_copy(der%mesh%np, rho, rho_corrected)
233 vh_correction = m_zero
234 add_lm = 1
235 do ll = 0, this%maxl
236 do mm = -ll, ll
237 do ip = 1, der%mesh%np
238 rho_corrected(ip) = rho_corrected(ip) - mult(add_lm)*betal(add_lm)*this%aux(ip, add_lm)*this%gaussian(ip)
239 end do
240 call lalg_axpy(der%mesh%np, mult(add_lm), this%phi(:, add_lm), vh_correction)
241 add_lm = add_lm + 1
242 end do
243 end do
244
245 safe_deallocate_a(mult)
246 safe_deallocate_a(betal)
247
248 case (corr_exact)
249
250 do ip = 1, der%mesh%np
251 vh_correction(ip) = m_zero
252 end do
253
254 do ip = der%mesh%np + 1, der%mesh%np_part
255 vv = m_zero
256 do ip2 = 1, der%mesh%np
257 rr = norm2((der%mesh%x(ip, 1:der%dim) - der%mesh%x(ip2, 1:der%dim)))
258 vv = vv + rho(ip2)/rr
259 end do
260 vh_correction(ip) = der%mesh%volume_element*vv
261 end do
262
263 assert(.not. nl_operator_compact_boundaries())
264
265 call dderivatives_lapl(der, vh_correction, rho_corrected, set_bc = .false.)
266
267 do ip = 1, der%mesh%np
268 rho_corrected(ip) = rho(ip) + m_one/(m_four*m_pi)*rho_corrected(ip)
269 end do
270
271 end select
272
273 call profiling_out("POISSON_CORRECT")
274 pop_sub(correct_rho)
275 end subroutine correct_rho
276
277
278 ! ---------------------------------------------------------
279 subroutine get_multipoles(this, mesh, rho, ml, mult)
280 type(poisson_corr_t), intent(in) :: this
281 type(mesh_t), intent(in) :: mesh
282 real(real64), intent(in) :: rho(:)
283 integer, intent(in) :: ml
284 real(real64), intent(out) :: mult((ml+1)**2)
285
286 integer :: add_lm, ll, mm
287
288 push_sub(get_multipoles)
290 mult(:) = m_zero
291 add_lm = 1
292 do ll = 0, ml
293 do mm = -ll, ll
294 mult(add_lm) = dmf_dotp(mesh, rho, this%aux(:, add_lm))
295 add_lm = add_lm + 1
296 end do
297 end do
298
299 pop_sub(get_multipoles)
300 end subroutine get_multipoles
301
302 ! ---------------------------------------------------------
303 subroutine internal_laplacian_op(xx, yy, userdata)
304 real(real64), contiguous, intent(in) :: xx(:)
305 real(real64), contiguous, intent(out) :: yy(:)
306 type(c_ptr), intent(in) :: userdata(:)
307
308 real(real64), allocatable :: xx_tmp(:)
309
310 push_sub(internal_laplacian_op)
311
312 safe_allocate(xx_tmp(der_pointer%mesh%np_part))
313 call lalg_copy(der_pointer%mesh%np, xx, xx_tmp)
314 call dderivatives_lapl(der_pointer, xx_tmp, yy)
315
316 safe_deallocate_a(xx_tmp)
317 pop_sub(internal_laplacian_op)
318
319 end subroutine internal_laplacian_op
320
321
322 ! ---------------------------------------------------------
323 real(real64) function internal_dotp(xx, yy) result(res)
324 real(real64), intent(in) :: xx(:)
325 real(real64), intent(in) :: yy(:)
326
327 push_sub(internal_dotp)
328
329 res = dmf_dotp(mesh_pointer, xx, yy)
330 pop_sub(internal_dotp)
331 end function internal_dotp
332
333
334 ! ---------------------------------------------------------
335 subroutine poisson_boundary_conditions(this, mesh, rho, pot)
336 type(poisson_corr_t), intent(in) :: this
337 type(mesh_t), intent(in) :: mesh
338 real(real64), intent(in) :: rho(:)
339 real(real64), intent(inout) :: pot(:)
340
341 integer :: ip, add_lm, ll, mm, bp_lower
342 real(real64) :: xx(mesh%box%dim), rr, s1, sa
343 real(real64), allocatable :: mult(:)
344
346
347 assert(mesh%box%dim == 3)
348
349 safe_allocate(mult(1:(this%maxl+1)**2))
350
351 call get_multipoles(this, mesh, rho, this%maxl, mult)
352
353 bp_lower = mesh%np + 1
354 if (mesh%parallel_in_domains) then
355 bp_lower = bp_lower + mesh%pv%np_ghost
356 end if
357
358 pot(bp_lower:mesh%np_part) = m_zero
359 do ip = bp_lower, mesh%np_part ! boundary conditions
360 call mesh_r(mesh, ip, rr, coords = xx)
361 add_lm = 1
362 do ll = 0, this%maxl
363 s1 = m_four*m_pi/((m_two*ll + m_one)*rr**(ll + 1))
364 do mm = -ll, ll
365 call ylmr_real(xx, ll, mm, sa)
366 pot(ip) = pot(ip) + sa * mult(add_lm) * s1
367 add_lm = add_lm+1
368 end do
369 end do
370 end do
371
372 safe_deallocate_a(mult)
375
377
378!! Local Variables:
379!! mode: f90
380!! coding: utf-8
381!! End:
Define which routines can be seen from the outside.
Definition: loct_math.F90:151
double exp(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
real(real64), parameter, public m_zero
Definition: global.F90:190
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:188
real(real64), parameter, public m_epsilon
Definition: global.F90:206
real(real64), parameter, public m_half
Definition: global.F90:196
real(real64), parameter, public m_one
Definition: global.F90:191
real(real64), parameter, public m_five
Definition: global.F90:195
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public ylmr_real(xx, li, mi, ylm)
This is a Numerical Recipes-based subroutine computes real spherical harmonics ylm at position (x,...
Definition: math.F90:378
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:340
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1097
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1069
This module defines non-local operators.
subroutine get_multipoles(this, mesh, rho, ml, mult)
subroutine, public poisson_corrections_end(this)
subroutine, public internal_laplacian_op(xx, yy, userdata)
real(real64) function, public internal_dotp(xx, yy)
subroutine, public poisson_boundary_conditions(this, mesh, rho, pot)
subroutine, public poisson_corrections_init(this, namespace, space, ml, mesh)
real(real64), parameter alpha_
type(mesh_t), pointer, public mesh_pointer
subroutine, public correct_rho(this, der, rho, rho_corrected, vh_correction)
type(derivatives_t), pointer, public der_pointer
real(real64) function isubl(ll, xx)