Octopus
poisson_test.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
23 use debug_oct_m
24 use global_oct_m
25 use io_oct_m
29 use mesh_oct_m
32 use mpi_oct_m
34 use parser_oct_m
37 use space_oct_m
38 use unit_oct_m
40
41 implicit none
42
43 private
44 public :: &
46
47contains
48
49 !-----------------------------------------------------------------
56 subroutine poisson_test(this, space, mesh, latt, namespace, repetitions)
57 type(poisson_t), intent(in) :: this
58 class(space_t), intent(in) :: space
59 class(mesh_t), intent(in) :: mesh
60 type(lattice_vectors_t), intent(in) :: latt
61 type(namespace_t), intent(in) :: namespace
62 integer, intent(in) :: repetitions
63
64 real(real64), allocatable :: rho(:), vh(:), vh_exact(:), xx(:, :), xx_per(:)
65 real(real64) :: alpha, beta, rr, delta, ralpha, hartree_nrg_num, &
66 hartree_nrg_analyt, lcl_hartree_nrg
67 real(real64) :: total_charge
68 integer :: ip, ierr, iunit, nn, n_gaussians, itime, icell
69 real(real64) :: threshold
70 type(lattice_iterator_t) :: latt_iter
71
72 push_sub(poisson_test)
73
74 if (mesh%box%dim == 1) then
75 call messages_not_implemented('Poisson test for 1D case', namespace=namespace)
76 end if
77
78 !%Variable PoissonTestPeriodicThreshold
79 !%Type float
80 !%Default 1e-5
81 !%Section Hamiltonian::Poisson
82 !%Description
83 !% This threshold determines the accuracy of the periodic copies of
84 !% the Gaussian charge distribution that are taken into account when
85 !% computing the analytical solution for periodic systems.
86 !% Be aware that the default leads to good results for systems
87 !% that are periodic in 1D - for 3D it is very costly because of the
88 !% large number of copies needed.
89 !%End
90 call parse_variable(namespace, 'PoissonTestPeriodicThreshold', 1e-5_real64, threshold)
91
92 ! Use two gaussians with different sign
93 n_gaussians = 2
94
95 safe_allocate( rho(1:mesh%np))
96 safe_allocate( vh(1:mesh%np))
97 safe_allocate(vh_exact(1:mesh%np))
98 safe_allocate(xx(1:space%dim, 1:n_gaussians))
99 safe_allocate(xx_per(1:space%dim))
100
101 rho = m_zero
102 vh = m_zero
103 vh_exact = m_zero
104
105 alpha = m_four*mesh%spacing(1)
106 write(message(1),'(a,f14.6)') "Info: The alpha value is ", alpha
107 write(message(2),'(a)') " Higher values of alpha lead to more physical densities and more reliable results."
108 call messages_info(2, namespace=namespace)
109 beta = m_one / (alpha**space%dim * sqrt(m_pi)**space%dim)
110
111 write(message(1), '(a)') 'Building the Gaussian distribution of charge...'
112 call messages_info(1, namespace=namespace)
113
114 ! Set the centers of the Gaussians by hand
115 xx(1, 1) = m_one
116 xx(2, 1) = -m_half
117 if (space%dim == 3) xx(3, 1) = m_two
118 xx(1, 2) = -m_two
119 xx(2, 2) = m_zero
120 if (space%dim == 3) xx(3, 2) = -m_one
121 xx = xx * alpha
122
123 ! Density as sum of Gaussians
124 rho = m_zero
125 do nn = 1, n_gaussians
126 do ip = 1, mesh%np
127 call mesh_r(mesh, ip, rr, origin = xx(:, nn))
128 rho(ip) = rho(ip) + (-1)**nn * beta*exp(-(rr/alpha)**2)
129 end do
130 end do
131
132 total_charge = dmf_integrate(mesh, rho)
133
134 write(message(1), '(a,e23.16)') 'Total charge of the Gaussian distribution', total_charge
135 call messages_info(1, namespace=namespace)
136
137 write(message(1), '(a)') 'Computing exact potential.'
138 call messages_info(1, namespace=namespace)
139
140 ! This builds analytically its potential
141 vh_exact = m_zero
142 latt_iter = lattice_iterator_t(latt, m_one/threshold)
143 do nn = 1, n_gaussians
144 ! sum over all periodic copies for each Gaussian
145 write(message(1), '(a,i2,a,i9,a)') 'Computing Gaussian ', nn, ' for ', latt_iter%n_cells, ' periodic copies.'
146 call messages_info(1, namespace=namespace)
147
148 do icell = 1, latt_iter%n_cells
149 xx_per = xx(:, nn) + latt_iter%get(icell)
150 !$omp parallel do private(rr, ralpha)
151 do ip = 1, mesh%np
152 call mesh_r(mesh, ip, rr, origin=xx_per)
153 select case (space%dim)
154 case (3)
155 if (rr > r_small) then
156 vh_exact(ip) = vh_exact(ip) + (-1)**nn * loct_erf(rr/alpha)/rr
157 else
158 vh_exact(ip) = vh_exact(ip) + (-1)**nn * (m_two/sqrt(m_pi))/alpha
159 end if
160 case (2)
161 ralpha = rr**2/(m_two*alpha**2)
162 if (ralpha < 100.0_real64) then
163 vh_exact(ip) = vh_exact(ip) + (-1)**nn * beta * (m_pi)**(m_three*m_half) * alpha * exp(-rr**2/(m_two*alpha**2)) * &
164 loct_bessel_in(0, rr**2/(m_two*alpha**2))
165 else
166 vh_exact(ip) = vh_exact(ip) + (-1)**nn * beta * (m_pi)**(m_three*m_half) * alpha * &
167 (m_one/sqrt(m_two*m_pi*ralpha))
168 end if
169 end select
170 end do
171 end do
172 end do
173
174 ! This calculates the numerical potential
175 do itime = 1, repetitions
176 call dpoisson_solve(this, namespace, vh, rho)
177 end do
178
179 ! Output results
180 iunit = io_open("hartree_results", namespace, action='write')
181 delta = dmf_nrm2(mesh, vh-vh_exact)
182 write(iunit, '(a,e23.16)') 'Hartree test (abs.) = ', delta
183 delta = delta/dmf_nrm2(mesh, vh_exact)
184 write(iunit, '(a,e23.16)') 'Hartree test (rel.) = ', delta
185
186 ! Calculate the numerical Hartree energy (serially)
187 lcl_hartree_nrg = m_zero
188 do ip = 1, mesh%np
189 lcl_hartree_nrg = lcl_hartree_nrg + rho(ip) * vh(ip)
190 end do
191 lcl_hartree_nrg = lcl_hartree_nrg * mesh%spacing(1) * mesh%spacing(2) * mesh%spacing(3)/m_two
192#ifdef HAVE_MPI
193 call mpi_reduce(lcl_hartree_nrg, hartree_nrg_num, 1, &
194 mpi_double_precision, mpi_sum, 0, mpi_comm_world, mpi_err)
195 if (mpi_err /= 0) then
196 write(message(1),'(a)') "MPI error in MPI_Reduce; subroutine poisson_test of file poisson.F90"
197 call messages_warning(1, namespace=namespace)
198 end if
199#else
200 hartree_nrg_num = lcl_hartree_nrg
201#endif
202
203 ! Calculate the analytical Hartree energy (serially, discrete - not exactly exact)
204 lcl_hartree_nrg = m_zero
205 do ip = 1, mesh%np
206 lcl_hartree_nrg = lcl_hartree_nrg + rho(ip) * vh_exact(ip)
207 end do
208 lcl_hartree_nrg = lcl_hartree_nrg * mesh%spacing(1) * mesh%spacing(2) * mesh%spacing(3) / m_two
209#ifdef HAVE_MPI
210 call mpi_reduce(lcl_hartree_nrg, hartree_nrg_analyt, 1, &
211 mpi_double_precision, mpi_sum, 0, mpi_comm_world, mpi_err)
212 if (mpi_err /= 0) then
213 write(message(1),'(a)') "MPI error in MPI_Reduce; subroutine poisson_test of file poisson.F90"
214 call messages_warning(1, namespace=namespace)
215 end if
216#else
217 hartree_nrg_analyt = lcl_hartree_nrg
218#endif
219
220 write(iunit, '(a)')
221
222 if (mpi_world%rank == 0) then
223 write(iunit,'(a,e23.16)') 'Hartree Energy (numerical) =', hartree_nrg_num, 'Hartree Energy (analytical) =',hartree_nrg_analyt
224 end if
225
226 call io_close(iunit)
227
228 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_rho", namespace, space, &
229 mesh, rho, unit_one, ierr)
230 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_exact", namespace, space, &
231 mesh, vh_exact, unit_one, ierr)
232 call dio_function_output (io_function_fill_how('AxisX'), ".", "poisson_test_numerical", namespace, space, &
233 mesh, vh, unit_one, ierr)
234 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_rho", namespace, space, &
235 mesh, rho, unit_one, ierr)
236 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_exact", namespace, space, &
237 mesh, vh_exact, unit_one, ierr)
238 call dio_function_output (io_function_fill_how('AxisY'), ".", "poisson_test_numerical", namespace, space, &
239 mesh, vh, unit_one, ierr)
240 ! not dimensionless, but no need for unit conversion for a test routine
241
242 safe_deallocate_a(rho)
243 safe_deallocate_a(vh)
244 safe_deallocate_a(vh_exact)
245 safe_deallocate_a(xx)
246
247 pop_sub(poisson_test)
248 end subroutine poisson_test
249
250end module poisson_test_oct_m
251
252!! Local Variables:
253!! mode: f90
254!! coding: utf-8
255!! End:
double exp(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_two
Definition: global.F90:190
real(real64), parameter, public r_small
Definition: global.F90:180
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_four
Definition: global.F90:192
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
real(real64), parameter, public m_half
Definition: global.F90:194
real(real64), parameter, public m_one
Definition: global.F90:189
real(real64), parameter, public m_three
Definition: global.F90:191
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:418
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:352
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
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_not_implemented(feature, namespace)
Definition: messages.F90:1113
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:537
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
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
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:892
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...
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
The following class implements a lattice iterator. It allows one to loop over all cells that are with...