49 para_env => logger%para_env
55 CALL check_pw_integral_and_poisson()
56 CALL check_mt2d_kernel()
57 print
'(A,ES16.7)',
'PW integral and MT2D kernel maximum scaled error: ', max_error
66 CHARACTER(LEN=13) :: value
67 CHARACTER(LEN=79) :: values
68 CHARACTER(LEN=92) :: slice_values
69 REAL(KIND=
dp),
DIMENSION(6) :: buffer, reference
70 REAL(KIND=
dp),
DIMENSION(7) :: slice_buffer, slice_reference
73 IF (index(
value,
"E-101") <= 0)
THEN
74 error stop
"Cube value format must preserve three-digit negative exponents."
77 reference = [0.0_dp, -0.91458e-35_dp, 3.33004e-101_dp, &
78 -1.32487e-103_dp, 1.0_dp, -1.0_dp]
80 values(79:79) = new_line(
"C")
81 IF (index(values,
"E-101") <= 0)
THEN
82 error stop
"Cube line format must preserve E-101."
84 IF (index(values,
"E-103") <= 0)
THEN
85 error stop
"Cube line format must preserve E-103."
88 IF (maxval(abs(buffer - reference)) > 1.0e-12_dp)
THEN
89 error stop
"Cube reader must parse adjacent explicit-exponent values."
92 slice_reference(1:6) = reference
93 slice_reference(7) = 0.27183e-123_dp
95 slice_values(79:79) = new_line(
"C")
98 IF (maxval(abs(slice_buffer - slice_reference)) > 1.0e-12_dp)
THEN
99 error stop
"Cube reader must parse multi-line z-slices."
108 SUBROUTINE check_copy(mode)
109 INTEGER,
INTENT(IN) :: mode
111 COMPLEX(dp),
PARAMETER :: untouched = (-999.0_dp, 17.0_dp)
113 COMPLEX(dp) :: expected
114 INTEGER :: dimensions(1), i, j, nsource, ntarget, &
119 rank = para_env%mepos
121 IF (mode == 6 .OR. (mode >= 7 .AND. rank == 0)) nsource = 0
123 IF (mode == 3 .OR. mode == 8) owner = mod(rank + 1, para_env%num_pe)
125 IF (mode == 4) ntarget = nsource - 1
126 IF (mode == 5) ntarget = nsource + 1
127 IF (mode == 8) ntarget = merge(0, 7, owner == 0)
128 ALLOCATE (source_grid%g_hat(3, nsource), target_grid%g_hat(3, ntarget))
129 ALLOCATE (source%array(nsource), destination%array(ntarget))
130 source%pw_grid => source_grid
131 destination%pw_grid => target_grid
132 dimensions = [para_env%num_pe]
133 CALL source_grid%para%group%create(para_env, 1, dimensions)
134 target_grid%para%group = source_grid%para%group
135 source_grid%ngpts_cut_local = nsource
136 target_grid%ngpts_cut_local = ntarget
138 source_grid%g_hat(:, i) = [i, rank, 0]
139 source%array(i) = cmplx(i + 11*rank, -i - 3*rank,
dp)
143 IF (mode == 1 .OR. (mode == 2 .AND. rank == 0)) j = ntarget + 1 - i
144 target_grid%g_hat(:, i) = [j, owner, 0]
146 destination%array(:) = untouched
149 j = target_grid%g_hat(1, i)
150 expected = cmplx(j + 11*owner, -j - 3*owner,
dp)
151 IF (mode == 5 .AND. j > nsource) expected = untouched
152 IF (abs(destination%array(i) - expected) > 1.e-14_dp) error stop
'Incorrect PW copy'
154 DEALLOCATE (source%array, destination%array)
155 CALL source_grid%para%group%free()
156 END SUBROUTINE check_copy
161 SUBROUTINE check_pw_integral_and_poisson()
162 REAL(dp),
PARAMETER :: step = 5.e-4_dp, &
163 strain_steps(4) = [step, -step, 2.0_dp*step, -2.0_dp*step]
165 COMPLEX(dp) :: a_mode, b_mode
166 INTEGER :: axis, ig, sign_step, span, sumtype, test
167 REAL(dp) :: cell(3, 3), derivative, energy, energy_dv, energy_v, energy_v_dv, expected, &
168 expected_real, kernel, reference, shifted_g(3), strain_energy(4), stress(3, 3), &
169 stress_dv(3, 3), stress_only(3, 3), stress_v(3, 3), stress_v_dv(3, 3)
172 potential, potential_v_dv
181 cell(axis, axis) = 7.0_dp**(1.0_dp/3.0_dp)
183 a_mode = cmplx(0.4_dp, -0.2_dp, dp)
184 b_mode = cmplx(-0.7_dp, 0.9_dp, dp)
189 CALL pw_grid_create(grid, comm, cell, grid_span=span, npts=[5, 5, 5], odd=.true., fft_usage=.false.)
192 CALL a_real%create(grid)
193 CALL b_real%create(grid)
194 CALL potential%create(grid)
195 CALL potential_v_dv%create(grid)
197 CALL gradient(axis)%create(grid)
198 CALL gradient_v_dv(axis)%create(grid)
200 ALLOCATE (poisson%pw_pools(1))
204 poisson%parameters%periodic = [1, 1, 0]
205 poisson%parameters%mt_alpha = 1.0_dp
212 expected_real = 0.0_dp
214 IF (grid%have_g0)
THEN
219 expected_real = 6.0_dp
220 reference = 6.0_dp*mt2d_kernel_reference([0.0_dp, 0.0_dp, 0.0_dp], 3, cell(3, 3))
222 DO ig = 1, grid%ngpts_cut_local
223 IF (any(grid%g_hat(2:3, ig) /= 0)) cycle
224 IF (grid%g_hat(1, ig) == 1)
THEN
227 ELSE IF (grid%g_hat(1, ig) == -1)
THEN
228 a%array(ig) = conjg(a_mode)
229 b%array(ig) = conjg(b_mode)
232 expected = expected + 2.0_dp*real(conjg(a_mode)*b_mode, dp)
233 expected_real = expected_real + 2.0_dp*real(a_mode, dp)*real(b_mode, dp)
234 kernel = mt2d_kernel_reference([2.0_dp*
pi/cell(1, 1), 0.0_dp, 0.0_dp], 3, cell(3, 3))
235 reference = reference + 2.0_dp*real(conjg(a_mode)*b_mode, dp)*kernel
237 a_real%array = real(a%array, dp)
238 b_real%array = real(b%array, dp)
242 CALL check_error(
pw_integral_ab(a, b, sumtype=sumtype), 7.0_dp*expected, 3.e-14_dp)
243 CALL check_error(
pw_integral_ab(a, b, sumtype=sumtype, just_sum=.true.), expected, 3.e-14_dp)
244 CALL check_error(
pw_integral_ab(a_real, b_real, sumtype=sumtype), 7.0_dp*expected_real, 3.e-14_dp)
245 CALL check_error(
pw_integral_ab(a_real, b_real, sumtype=sumtype, just_sum=.true.), &
246 expected_real, 3.e-14_dp)
247 CALL check_error(
pw_integral_ab(a, b_real, sumtype=sumtype), 7.0_dp*expected_real, 3.e-14_dp)
248 CALL check_error(
pw_integral_ab(a_real, b, sumtype=sumtype), 7.0_dp*expected_real, 3.e-14_dp)
251 CALL pw_poisson_solve(poisson, a, energy_dv, dvhartree=gradient, h_stress=stress_dv, aux_density=b)
252 CALL pw_poisson_solve(poisson, a, energy_v, potential, h_stress=stress_v, aux_density=b)
253 CALL pw_poisson_solve(poisson, a, energy_v_dv, potential_v_dv, dvhartree=gradient_v_dv, &
254 h_stress=stress_v_dv, aux_density=b)
256 CALL check_error(energy, 0.5_dp*7.0_dp*reference, 3.e-13_dp)
257 CALL check_error(energy_dv, energy, 3.e-13_dp)
258 CALL check_error(energy_v, energy, 3.e-13_dp)
259 CALL check_error(energy_v_dv, energy, 3.e-13_dp)
260 CALL check_error(maxval(abs(stress_dv - stress)), 0.0_dp, 3.e-11_dp)
261 CALL check_error(maxval(abs(stress_v - stress)), 0.0_dp, 3.e-11_dp)
262 CALL check_error(maxval(abs(stress_v_dv - stress)), 0.0_dp, 3.e-11_dp)
263 CALL check_error(maxval(abs(stress_only - stress)), 0.0_dp, 3.e-11_dp)
269 shifted_g = [2.0_dp*
pi/cell(1, 1)/(1.0_dp + strain_steps(sign_step)), 0.0_dp, 0.0_dp]
270 reference = 6.0_dp*mt2d_kernel_reference([0.0_dp, 0.0_dp, 0.0_dp], 3, cell(3, 3)) &
271 + 2.0_dp*real(conjg(a_mode)*b_mode, dp)*mt2d_kernel_reference(shifted_g, 3, cell(3, 3))
272 strain_energy(sign_step) = 0.5_dp*7.0_dp*reference/(1.0_dp + strain_steps(sign_step))
274 derivative = (8.0_dp*(strain_energy(1) - strain_energy(2)) &
275 - strain_energy(3) + strain_energy(4))/(12.0_dp*step)
276 CALL check_error(stress(1, 1) + derivative, 0.0_dp, 3.e-9_dp)
278 DO ig = 1, grid%ngpts_cut_local
279 kernel = mt2d_kernel_reference(grid%g(:, ig), 3, cell(3, 3))
280 CALL check_error(abs(potential%array(ig) - kernel*a%array(ig)), 0.0_dp, 3.e-13_dp)
281 CALL check_error(abs(potential_v_dv%array(ig) - kernel*a%array(ig)), 0.0_dp, 3.e-13_dp)
283 CALL check_error(abs(gradient(axis)%array(ig) &
284 - cmplx(0.0_dp, grid%g(axis, ig), dp)*kernel*a%array(ig)), 0.0_dp, 3.e-13_dp)
285 CALL check_error(abs(gradient_v_dv(axis)%array(ig) &
286 - cmplx(0.0_dp, grid%g(axis, ig), dp)*kernel*a%array(ig)), 0.0_dp, 3.e-13_dp)
290 CALL poisson%release()
293 CALL a_real%release()
294 CALL b_real%release()
295 CALL potential%release()
296 CALL potential_v_dv%release()
298 CALL gradient(axis)%release()
299 CALL gradient_v_dv(axis)%release()
303 END SUBROUTINE check_pw_integral_and_poisson
308 SUBROUTINE check_mt2d_kernel()
309 REAL(dp),
PARAMETER :: step = 3.e-4_dp, shifts(4) = [step, -step, 2.0_dp*step, -2.0_dp*step]
311 INTEGER :: alpha, beta, ip, iz, jp, miller(3), &
312 mode, modes(3, 5), sign_step
313 REAL(dp) :: derivative, g(3), h_inv(3, 3), kernel, &
314 lengths(3), shifted_g(3), &
315 shifted_kernel(4), strain(3, 3)
321 jp = mod(iz + 1, 3) + 1
322 lengths = [9.0_dp, 13.0_dp, 17.0_dp]
325 h_inv(alpha, alpha) = 1.0_dp/lengths(alpha)
327 h_inv(ip, jp) = -1.4_dp/(lengths(ip)*lengths(jp))
331 modes(iz, 2:3) = [1, 2]
333 modes(:, 5) = [1, 2, 1]
334 DO mode = 1,
SIZE(modes, 2)
335 miller = modes(:, mode)
336 g = 2.0_dp*
pi*matmul(transpose(h_inv), real(miller, dp))
338 CALL check_error(kernel, mt2d_kernel_reference(g, iz, lengths(iz)), 3.e-14_dp)
339 CALL check_error(maxval(abs(strain(iz, :))), 0.0_dp, 0.0_dp)
340 CALL check_error(maxval(abs(strain(:, iz))), 0.0_dp, 0.0_dp)
341 IF (mode <= 3)
CALL check_error(maxval(abs(strain)), 0.0_dp, 0.0_dp)
343 IF (alpha == iz) cycle
345 IF (beta == iz) cycle
349 IF (alpha == beta)
THEN
350 shifted_g(beta) = g(beta)/(1.0_dp + shifts(sign_step))
352 shifted_g(beta) = g(beta) - shifts(sign_step)*g(alpha)
354 shifted_kernel(sign_step) = mt2d_kernel_reference(shifted_g, iz, lengths(iz))
356 derivative = (8.0_dp*(shifted_kernel(1) - shifted_kernel(2)) &
357 - shifted_kernel(3) + shifted_kernel(4))/(12.0_dp*step)
358 CALL check_error(strain(alpha, beta), derivative, 3.e-9_dp)
363 END SUBROUTINE check_mt2d_kernel
372 FUNCTION mt2d_kernel_reference(g, iz, slab_size)
RESULT(kernel)
373 REAL(dp),
INTENT(IN) :: g(3)
374 INTEGER,
INTENT(IN) :: iz
375 REAL(dp),
INTENT(IN) :: slab_size
378 REAL(dp) :: g2, g_parallel(3), radius
381 IF (g2 == 0.0_dp)
THEN
382 kernel =
pi*slab_size**2/2.0_dp
385 g_parallel(iz) = 0.0_dp
386 radius = slab_size/2.0_dp
387 kernel =
fourpi/g2 -
fourpi/g2*cos(g(iz)*radius)*exp(-norm2(g_parallel)*radius)
389 END FUNCTION mt2d_kernel_reference
397 SUBROUTINE check_error(value, reference, tolerance)
398 REAL(dp),
INTENT(IN) ::
value, reference, tolerance
402 error = abs(
value - reference)/max(1.0_dp, abs(reference))
403 max_error = max(max_error, error)
404 IF (.NOT. (error <= tolerance))
THEN
405 print *,
'Coulomb check: value, reference, error, tolerance:',
value, reference, error, tolerance
406 error stop
'PW integral or MT2D kernel check failed'
408 END SUBROUTINE check_error
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
Defines the basic variable types.
integer, parameter, public dp
subroutine, public cp2k_finalize()
...
subroutine, public cp2k_init()
...
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
real(kind=dp), parameter, public fourpi
Interface to the message passing library MPI.
type(mp_comm_type), parameter, public mp_comm_world
subroutine, public mt2d_kernel_strain(g, special_dimension, slab_size, kernel, strain)
MT2D Coulomb kernel and its affine strain derivative in the periodic plane.
subroutine, public pw_copy_match(pw1, pw2)
copy a pw type variable
integer, parameter, public halfspace
integer, parameter, public fullspace
This module defines the grid data type and some basic operations on it.
subroutine, public pw_grid_release(pw_grid)
releases the given pw grid
integer, parameter, public do_accurate_sum
integer, parameter, public do_standard_sum
subroutine, public pw_poisson_set(poisson_env, cell_hmat, parameters, pw_pools, use_level, mt_super_ref_pw_grid, dct_pw_grid, force_rebuild)
sets cell, grids and parameters used by the poisson solver You should call this at least once (and se...
functions related to the poisson solver on regular grids
integer, parameter, public pw_poisson_mt
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
subroutine, public pw_pool_create(pool, pw_grid, max_cache)
creates a pool for pw
Generate Gaussian cube files.
character(len= *), parameter, public cube_values_format
character(len= *), parameter, public cube_value_format
subroutine, public cube_read_values(values, buffer)
Read cube values from a character buffer.
subroutine check_cube_values()
Preserve three-digit cube exponents and parse adjacent values across z-slices.
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment
environment for the poisson solver