(git:6344619)
Loading...
Searching...
No Matches
kpoint_lattice_fft_unittest.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
8 USE fft_tools, ONLY: finalize_fft,&
10 USE kinds, ONLY: dp
23 USE mathconstants, ONLY: gaussi,&
24 twopi,&
25 z_zero
26 USE message_passing, ONLY: mp_comm_type,&
29
30 IMPLICIT NONE
31
32 INTEGER, PARAMETER :: base_block = 2, base_cell = 8, base_n = 16, &
33 base_ncol = 3, ncell = 31, nkp = 64, &
34 nround = 16, nselected = 3
35 INTEGER, PARAMETER :: large_block = 1000, large_ncol = 1000, &
36 large_num_pe = 16
37 COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: inverse_k
38 COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :) :: state_inverse_k
39 COMPLEX(KIND=dp), DIMENSION(2, 3, nkp) :: direct, transformed
40 COMPLEX(KIND=dp), DIMENSION(2, 3, nround) :: reconstructed, round_k
41 COMPLEX(KIND=dp), DIMENSION(2, 3, nselected) :: selected_transformed
42 INTEGER :: d, i, icell, info, j, jcell, ik, ix, iy, iz
43 INTEGER, ALLOCATABLE, DIMENSION(:) :: correction_indices
44 INTEGER, DIMENSION(3) :: base_dims, delta, large_dims
45 INTEGER, DIMENSION(3, base_cell) :: base_index
46 INTEGER, DIMENSION(3) :: nkp_grid
47 INTEGER, DIMENSION(3, ncell) :: index_to_cell
48 INTEGER, DIMENSION(3, nround) :: round_index
49 INTEGER, DIMENSION(nselected) :: selected_kpoints
50 LOGICAL :: used_fft
51 REAL(kind=dp), DIMENSION(3, 3) :: hmat
52 REAL(kind=dp) :: base_residual_norm, corrected_projection_error, &
53 corrected_residual_norm, cost_ratio, &
54 expected_cost_ratio, imaginary_residual, &
55 large_block_real, large_ncell_real, &
56 large_ncol_real, projection_error
57 REAL(kind=dp), DIMENSION(3, base_cell) :: base_xkp
58 REAL(kind=dp), DIMENSION(base_n, base_n) :: base_overlap
59 REAL(kind=dp), DIMENSION(base_n, base_n) :: defect_operator
60 REAL(kind=dp), DIMENSION(base_n, base_ncol) :: base_input, base_input_rotated, &
61 base_output, base_output_rotated, &
62 base_state_output, defect_residual
63 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: coarse_inverse, defect_base_output, &
64 defect_corrected_output, local_operator, &
65 selected_output, selected_rhs
66 REAL(kind=dp), DIMENSION(base_ncol, base_ncol) :: column_rotation
67 REAL(kind=dp), DIMENSION(3, nkp) :: xkp, xkp_bad
68 REAL(kind=dp), DIMENSION(2, 3, ncell) :: values_rs
69 REAL(kind=dp), DIMENSION(2, 3, nround) :: round_rs
70 TYPE(mp_comm_type) :: mp_comm
71 TYPE(k_grid_to_cell_work_type) :: inverse_work
72 REAL(kind=dp), DIMENSION(9) :: subset_weights
73 COMPLEX(KIND=dp), DIMENSION(2, 3, ncell) :: weighted_reference, weighted_result
74
75 CALL mp_world_init(mp_comm)
76 CALL check_image_reconstruction(mp_comm)
77 CALL init_fft("FFTSG", alltoall=.false., pool_limit=4, &
78 wisdom_file="", plan_style=1)
79
80 nkp_grid = [4, 4, 4]
81 hmat = reshape([4.0_dp, 0.1_dp, 0.2_dp, &
82 0.0_dp, 5.0_dp, 0.3_dp, &
83 0.0_dp, 0.0_dp, 6.0_dp], [3, 3])
84
85 ik = 0
86 DO iz = 0, nkp_grid(3) - 1
87 DO iy = 0, nkp_grid(2) - 1
88 DO ix = 0, nkp_grid(1) - 1
89 ik = ik + 1
90 xkp(:, ik) = [(real(ix, dp) + 0.5_dp)/real(nkp_grid(1), dp), &
91 REAL(iy, dp)/REAL(nkp_grid(2), dp), &
92 (REAL(iz, dp) + 0.25_dp)/REAL(nkp_grid(3), dp)]
93 END DO
94 END DO
95 END DO
96 IF (.NOT. regular_kpoint_grid(xkp, nkp_grid)) error stop "Regular k-point grid not recognized"
97
98 DO icell = 1, ncell
99 index_to_cell(:, icell) = [modulo(3*icell + 1, 11) - 5, &
100 modulo(5*icell + 2, 9) - 4, &
101 modulo(7*icell + 3, 7) - 3]
102 DO d = 1, 3
103 values_rs(1, d, icell) = sin(0.13_dp*real(icell + 2*d, dp))
104 values_rs(2, d, icell) = cos(0.17_dp*real(2*icell - d, dp))
105 END DO
106 END DO
107
108 CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, transformed, used_fft)
109 IF (.NOT. used_fft) error stop "Complete regular grid did not use lattice FFT"
110 CALL direct_reference(values_rs, index_to_cell, xkp, direct)
111 IF (maxval(abs(transformed - direct)) > 2.0e-12_dp) THEN
112 error stop "Shifted lattice FFT differs from direct transform"
113 END IF
114
115 selected_kpoints = [2, 31, 64]
116 CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, selected_transformed, &
117 used_fft, selected_kpoints=selected_kpoints)
118 IF (.NOT. used_fft) error stop "Selected distributed output did not use lattice FFT"
119 IF (maxval(abs(selected_transformed - direct(:, :, selected_kpoints))) > 2.0e-12_dp) THEN
120 error stop "Selected lattice-FFT output differs from the full transform"
121 END IF
122
123 CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, transformed, used_fft, 2, hmat)
124 IF (.NOT. used_fft) error stop "Derivative did not use lattice FFT"
125 CALL direct_reference(values_rs, index_to_cell, xkp, direct, 2, hmat)
126 IF (maxval(abs(transformed - direct)) > 5.0e-12_dp) THEN
127 error stop "Lattice-FFT derivative differs from direct transform"
128 END IF
129
130 nkp_grid = [4, 4, 1]
131 ik = 0
132 DO iy = 0, nkp_grid(2) - 1
133 DO ix = 0, nkp_grid(1) - 1
134 ik = ik + 1
135 xkp(:, ik) = [(real(ix, dp) + 0.5_dp)/real(nkp_grid(1), dp), &
136 REAL(iy, dp)/REAL(nkp_grid(2), dp), 0.0_dp]
137 END DO
138 END DO
139 CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp(:, 1:ik), nkp_grid, &
140 transformed(:, :, 1:ik), used_fft)
141 IF (.NOT. used_fft) error stop "Singleton grid direction did not use padded lattice FFT"
142 CALL direct_reference(values_rs, index_to_cell, xkp(:, 1:ik), direct(:, :, 1:ik))
143 IF (maxval(abs(transformed(:, :, 1:ik) - direct(:, :, 1:ik))) > 2.0e-12_dp) THEN
144 error stop "Padded lattice FFT differs from direct transform"
145 END IF
146
147 icell = 0
148 DO iy = 0, nkp_grid(2) - 1
149 DO ix = 0, nkp_grid(1) - 1
150 icell = icell + 1
151 round_index(:, icell) = [ix, iy, 0]
152 round_rs(:, :, icell) = values_rs(:, :, icell)
153 END DO
154 END DO
155 CALL cell_to_k_grid_fft(round_rs, round_index, xkp(:, 1:ik), nkp_grid, round_k, used_fft)
156 IF (.NOT. used_fft) error stop "Round-trip forward transform did not use lattice FFT"
157 CALL k_grid_to_cell_fft(round_k, xkp(:, 1:ik), nkp_grid, round_index, reconstructed, used_fft)
158 IF (.NOT. used_fft) error stop "Round-trip inverse transform did not use lattice FFT"
159 IF (maxval(abs(reconstructed - cmplx(round_rs, kind=dp))) > 3.0e-12_dp) THEN
160 error stop "Forward/inverse lattice-FFT round trip is inconsistent"
161 END IF
162
163 ! An incomplete shifted grid uses the supplied weights exactly, including
164 ! negative translations. Reuse the preparation for separate matrix batches.
165 subset_weights = [(real(ik, dp)/45.0_dp, ik=1, 9)]
166 weighted_reference = z_zero
167 DO icell = 1, ncell
168 DO ik = 1, 9
169 weighted_reference(:, :, icell) = weighted_reference(:, :, icell) + subset_weights(ik)* &
170 exp(-gaussi*twopi*sum(xkp(:, ik)*real(index_to_cell(:, icell), dp)))*round_k(:, :, ik)
171 END DO
172 END DO
173 CALL k_grid_to_cell_prepare(inverse_work, xkp(:, 1:9), nkp_grid, index_to_cell, &
174 weights=subset_weights, allow_incomplete=.true.)
175 DO i = 1, 2
176 CALL k_grid_to_cell_execute(inverse_work, round_k(i:i, :, 1:9), weighted_result(i:i, :, :), used_fft)
177 IF (.NOT. used_fft) error stop "Prepared incomplete grid did not use FFT"
178 END DO
179 IF (maxval(abs(weighted_result - weighted_reference)) > 3.0e-12_dp) THEN
180 error stop "Prepared weighted inverse differs from explicit phase sum"
181 END IF
182 CALL k_grid_to_cell_fft(round_k(:, :, 1:9), xkp(:, 1:9), nkp_grid, index_to_cell, weighted_result, &
183 used_fft, weights=subset_weights, allow_incomplete=.true.)
184 IF (maxval(abs(weighted_result - weighted_reference)) > 3.0e-12_dp) THEN
185 error stop "One-shot and prepared inverse transforms disagree"
186 END IF
187 CALL k_grid_to_cell_prepare(inverse_work, xkp(:, 1:9), nkp_grid, index_to_cell, &
188 weights=2.0_dp*subset_weights, allow_incomplete=.true.)
189 CALL k_grid_to_cell_execute(inverse_work, round_k(:, :, 1:9), weighted_result, used_fft)
190 IF (maxval(abs(weighted_result - 2.0_dp*weighted_reference)) > 6.0e-12_dp) THEN
191 error stop "Repreparing inverse transform retained stale weights"
192 END IF
193 CALL k_grid_to_cell_release(inverse_work)
194 CALL k_grid_to_cell_release(inverse_work)
195
196 nkp_grid = [4, 4, 4]
197
198 xkp_bad = xkp
199 xkp_bad(1, nkp) = xkp_bad(1, nkp) + 0.03125_dp
200 CALL cell_to_k_grid_fft(values_rs, index_to_cell, xkp_bad, nkp_grid, transformed, used_fft)
201 IF (used_fft) error stop "Irregular k-point list incorrectly used lattice FFT"
202 CALL direct_reference(values_rs, index_to_cell, xkp_bad, direct)
203 IF (maxval(abs(transformed - direct)) > 1.0e-14_dp) THEN
204 error stop "Direct lattice-transform fallback is inconsistent"
205 END IF
206
207 ! Verify the block-circulant inverse against direct matrix application and right covariance.
208 base_dims = [4, 2, 1]
209 CALL lattice_grid(base_dims, base_index, base_xkp)
210 base_overlap = 0.0_dp
211 DO jcell = 1, base_cell
212 DO icell = 1, base_cell
213 delta = modulo(base_index(:, icell) - base_index(:, jcell), base_dims)
214 DO i = 1, base_block
215 IF (all(delta == 0)) THEN
216 base_overlap((icell - 1)*base_block + i, (jcell - 1)*base_block + i) = &
217 2.8_dp + 0.2_dp*real(i, kind=dp)
218 ELSE IF ((delta(1) == 1 .OR. delta(1) == base_dims(1) - 1) .AND. &
219 delta(2) == 0) THEN
220 base_overlap((icell - 1)*base_block + i, (jcell - 1)*base_block + i) = -0.12_dp
221 ELSE IF (delta(1) == 0 .AND. delta(2) == 1) THEN
222 base_overlap((icell - 1)*base_block + i, (jcell - 1)*base_block + i) = -0.08_dp
223 END IF
224 END DO
225 IF (all(delta == 0)) THEN
226 base_overlap((icell - 1)*base_block + 1, (jcell - 1)*base_block + 2) = 0.15_dp
227 base_overlap((icell - 1)*base_block + 2, (jcell - 1)*base_block + 1) = 0.15_dp
228 END IF
229 END DO
230 END DO
231 DO j = 1, base_ncol
232 DO i = 1, base_n
233 base_input(i, j) = sin(0.11_dp*real(2*i + 3*j, kind=dp))
234 END DO
235 END DO
236 CALL build_lattice_inverse(base_overlap, base_dims, inverse_k, projection_error, used_fft, info)
237 IF (info /= 0) error stop "Positive lattice overlap failed block Cholesky inversion"
238 IF (.NOT. used_fft) error stop "Block-circulant overlap construction did not use lattice FFT"
239 IF (projection_error > 2.0e-15_dp) error stop "Exact block-circulant overlap was changed by projection"
240 IF (lattice_fft_auto_select(base_dims, base_block, base_ncol, 1, 1, &
241 projection_error, used_fft, info)) THEN
242 error stop "Cost-aware lattice-FFT AUTO accepted a tiny eight-cell operator"
243 END IF
244 IF (.NOT. lattice_fft_auto_select(base_dims, 6, 8, 1, 2, &
245 projection_error, used_fft, info)) THEN
246 error stop "Cost-aware lattice-FFT AUTO rejected an economical eight-cell operator"
247 END IF
248 IF (lattice_fft_auto_select([4, 1, 1], 6, 8, 1, 2, &
249 projection_error, used_fft, info)) THEN
250 error stop "Conservative lattice-FFT AUTO accepted fewer than eight cells"
251 END IF
252 IF (lattice_fft_auto_select(base_dims, 6, 8, 1, 2, 2.0e-3_dp, used_fft, info)) THEN
253 error stop "Conservative lattice-FFT AUTO accepted a large projection error"
254 END IF
255 IF (lattice_fft_auto_select(base_dims, 6, 8, 17, 2, &
256 projection_error, used_fft, info)) THEN
257 error stop "Storage-aware lattice-FFT AUTO accepted too many state operators"
258 END IF
259 IF (lattice_fft_cost_ratio(base_dims, base_block, base_ncol, 1) <= 0.8_dp) THEN
260 error stop "Lattice-FFT cost estimate missed the tiny-batch overhead"
261 END IF
262 large_dims = [100, 100, 1]
263 large_ncell_real = real(product(large_dims), kind=dp)
264 large_block_real = real(large_block, kind=dp)
265 large_ncol_real = real(large_ncol, kind=dp)
266 expected_cost_ratio = ( &
267 large_ncell_real*large_block_real**2*large_ncol_real + &
268 4.0_dp*large_ncell_real*large_block_real*large_ncol_real* &
269 log(large_ncell_real)/log(2.0_dp) + &
270 8.0_dp*large_ncell_real*large_block_real + &
271 2.0_dp*large_ncell_real*large_block_real*large_ncol_real* &
272 log(real(large_num_pe + 1, kind=dp))/log(2.0_dp))/ &
273 ((large_ncell_real*large_block_real)**2*large_ncol_real)
274 cost_ratio = lattice_fft_cost_ratio(large_dims, large_block, large_ncol, large_num_pe)
275 IF (abs(cost_ratio - expected_cost_ratio) > 1.0e-14_dp*expected_cost_ratio) THEN
276 error stop "Lattice-FFT cost estimate overflowed for a large problem"
277 END IF
278 IF (abs(lattice_fft_storage_ratio(base_dims, 1) - 0.25_dp) > 1.0e-14_dp) THEN
279 error stop "Lattice-FFT storage estimate is inconsistent"
280 END IF
281 IF (abs(lattice_local_cost_ratio(base_dims, 1) - 0.28125_dp) > 1.0e-14_dp) THEN
282 error stop "Lattice local-correction cost estimate is inconsistent"
283 END IF
284 IF (abs(lattice_local_storage_ratio(base_dims, 3, 1) - 0.421875_dp) > 1.0e-14_dp) THEN
285 error stop "Lattice local-correction storage estimate is inconsistent"
286 END IF
287 CALL apply_lattice_inverse_dense(inverse_k, base_dims, base_input, base_output, &
288 used_fft, imaginary_residual)
289 IF (.NOT. used_fft) error stop "Block-circulant inverse application did not use lattice FFT"
290 IF (imaginary_residual > 3.0e-13_dp) error stop "Lattice inverse did not reconstruct a real matrix"
291 IF (maxval(abs(matmul(base_overlap, base_output) - base_input)) > 2.0e-11_dp) THEN
292 error stop "FFT block-circulant inverse differs from the dense operator inverse"
293 END IF
294
295 ALLOCATE (state_inverse_k(base_block, base_block, base_cell, base_ncol))
296 DO j = 1, base_ncol
297 state_inverse_k(:, :, :, j) = (0.5_dp + 0.25_dp*real(j, kind=dp))*inverse_k
298 END DO
299 CALL apply_lattice_state_inverse_dense(state_inverse_k, base_dims, base_input, &
300 base_state_output, used_fft, imaginary_residual)
301 IF (.NOT. used_fft) error stop "State-dependent inverse application did not use lattice FFT"
302 DO j = 1, base_ncol
303 IF (maxval(abs(base_state_output(:, j) - &
304 (0.5_dp + 0.25_dp*real(j, kind=dp))*base_output(:, j))) > 3.0e-12_dp) THEN
305 error stop "State-dependent lattice inverse used the wrong column operator"
306 END IF
307 END DO
308 DEALLOCATE (state_inverse_k)
309
310 column_rotation = 0.0_dp
311 column_rotation(1, 1) = cos(0.31_dp)
312 column_rotation(1, 2) = -sin(0.31_dp)
313 column_rotation(2, 1) = sin(0.31_dp)
314 column_rotation(2, 2) = cos(0.31_dp)
315 column_rotation(3, 3) = 1.0_dp
316 base_input_rotated = matmul(base_input, column_rotation)
317 CALL apply_lattice_inverse_dense(inverse_k, base_dims, base_input_rotated, &
318 base_output_rotated, used_fft)
319 IF (maxval(abs(base_output_rotated - matmul(base_output, column_rotation))) > 3.0e-12_dp) THEN
320 error stop "FFT lattice base is not right-covariant under orbital rotations"
321 END IF
322
323 ! Add one localized positive defect and verify the balanced cell correction.
324 defect_operator = base_overlap
325 defect_operator(5, 5) = defect_operator(5, 5) + 0.90_dp
326 defect_operator(6, 6) = defect_operator(6, 6) + 0.60_dp
327 CALL build_lattice_inverse(defect_operator, base_dims, inverse_k, projection_error, used_fft, info)
328 IF (info /= 0 .OR. .NOT. used_fft) error stop "Defective lattice operator failed construction"
329 IF (projection_error <= 1.0e-3_dp) error stop "Localized defect did not break lattice translations"
330 IF (lattice_fft_auto_select(base_dims, 6, 8, 1, 2, projection_error, used_fft, info)) THEN
331 error stop "Lattice-FFT AUTO accepted a localized defect"
332 END IF
334 defect_operator, base_dims, 1, correction_indices, local_operator, coarse_inverse, &
335 corrected_projection_error, info)
336 IF (info /= 0) error stop "Local correction coarse inverse failed"
337 IF (any(correction_indices /= [5, 6])) error stop "Local correction selected the wrong defect cell"
338 IF (corrected_projection_error >= projection_error) THEN
339 error stop "Local correction did not reduce the non-circulant residual"
340 END IF
341
342 ALLOCATE (defect_base_output(base_n, base_ncol), defect_corrected_output(base_n, base_ncol))
343 CALL apply_lattice_inverse_dense(inverse_k, base_dims, base_input, defect_base_output, used_fft)
344 CALL apply_balanced_local_inverse(inverse_k, base_dims, correction_indices, local_operator, &
345 coarse_inverse, base_input, defect_corrected_output)
346 defect_residual = matmul(defect_operator, defect_base_output) - base_input
347 base_residual_norm = norm2(defect_residual)
348 defect_residual = matmul(defect_operator, defect_corrected_output) - base_input
349 corrected_residual_norm = norm2(defect_residual)
350 IF (corrected_residual_norm >= base_residual_norm) THEN
351 error stop "Balanced local correction did not improve inverse application"
352 END IF
353 IF (sum(base_input*defect_corrected_output) <= 0.0_dp) THEN
354 error stop "Balanced local correction lost positive definiteness"
355 END IF
356
357 ALLOCATE (selected_rhs(base_n, SIZE(correction_indices)), &
358 selected_output(base_n, SIZE(correction_indices)))
359 selected_rhs(:, :) = local_operator
360 CALL apply_balanced_local_inverse(inverse_k, base_dims, correction_indices, local_operator, &
361 coarse_inverse, selected_rhs, selected_output)
362 selected_rhs = 0.0_dp
363 DO i = 1, SIZE(correction_indices)
364 selected_rhs(correction_indices(i), i) = 1.0_dp
365 END DO
366 IF (maxval(abs(selected_output - selected_rhs)) > 3.0e-11_dp) THEN
367 error stop "Balanced local correction is not exact in its selected subspace"
368 END IF
369 DEALLOCATE (coarse_inverse, correction_indices, defect_base_output, defect_corrected_output, &
370 local_operator, selected_output, selected_rhs)
371 DEALLOCATE (inverse_k)
372
373 CALL finalize_fft(mp_comm, "")
374 CALL mp_world_finalize()
375
376CONTAINS
377
378! **************************************************************************************************
379!> \brief Check triangular image storage against rskp_transform for both neighbor orientations.
380!> \param comm MPI communicator
381! **************************************************************************************************
383 USE cp_dbcsr_api, ONLY: &
385 dbcsr_finalize, dbcsr_finalize_lib, dbcsr_get_block_p, dbcsr_init_lib, dbcsr_p_type, &
386 dbcsr_put_block, dbcsr_release, dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_symmetric
391 USE kpoint_types, ONLY: kpoint_type
396 TYPE(mp_comm_type), INTENT(IN) :: comm
397
398 CHARACTER :: matrix_type, mirror_type
399 COMPLEX(dp) :: expected(5, 5), phase, RESULT(5, 5)
400 INTEGER :: atom, ik, image(3), img, io, mode, &
401 neighbor, orientation, owner
402 INTEGER, POINTER :: col_dist(:), images(:, :), &
403 process_grid(:, :), row_dist(:), &
404 sizes(:)
405 LOGICAL :: found
406 REAL(dp) :: expanded(1, 5, 5, 3), point(3), sign, &
407 values(2, 3)
408 REAL(dp), POINTER :: cosine(:, :), sine(:, :)
409 TYPE(cp_logger_type), POINTER :: logger
410 TYPE(dbcsr_distribution_type) :: distribution
411 TYPE(dbcsr_p_type), POINTER :: source(:, :)
412 TYPE(dbcsr_type) :: cosine_matrix, sine_matrix
413 TYPE(kpoint_type), POINTER :: points
414 TYPE(mp_para_env_type), POINTER :: para_env
415 TYPE(neighbor_list_p_type) :: neighbors
416
417 ALLOCATE (para_env)
418 CALL para_env%from_dup(comm)
419 io = -1
420 IF (comm%mepos == 0) io = default_output_unit
421 NULLIFY (logger)
422 CALL cp_logger_create(logger, para_env=para_env, default_global_unit_nr=io, &
423 close_global_unit_on_dealloc=.false.)
424 CALL cp_add_default_logger(logger)
425 CALL dbcsr_init_lib(comm%get_handle(), io)
426 ALLOCATE (process_grid(0:comm%num_pe - 1, 0:0), row_dist(2), col_dist(2), sizes(2))
427 process_grid(:, 0) = [(img, img=0, comm%num_pe - 1)]
428 col_dist = 0
429 sizes = [2, 3]
430 ALLOCATE (points, source(1, 3), images(3, 3))
431 ALLOCATE (points%cell_to_index(-1:1, 0:0, 0:0), points%sab_nl(1))
432 DO img = 1, 3
433 points%cell_to_index(img - 2, 0, 0) = img
434 images(:, img) = [img - 2, 0, 0]
435 ALLOCATE (source(1, img)%matrix)
436 END DO
437 values = reshape([0.3_dp, -0.2_dp, 0.7_dp, 0.1_dp, -0.4_dp, 0.6_dp], [2, 3])
438 DO mode = 1, 2
439 matrix_type = merge(dbcsr_type_symmetric, dbcsr_type_antisymmetric, mode == 1)
440 mirror_type = merge(dbcsr_type_antisymmetric, dbcsr_type_symmetric, mode == 1)
441 sign = merge(1.0_dp, -1.0_dp, mode == 1)
442 DO orientation = 1, 2
443 owner = modulo(orientation - 1, comm%num_pe)
444 row_dist = [owner, modulo(owner + 1, comm%num_pe)]
445 CALL dbcsr_distribution_new(distribution, group=comm%get_handle(), pgrid=process_grid, &
446 row_dist=row_dist, col_dist=col_dist)
447 atom = orientation
448 neighbor = 3 - orientation
449 image = [3 - 2*orientation, 0, 0]
450 CALL allocate_neighbor_list_set(points%sab_nl(1)%neighbor_list_set, symmetric=.true.)
451 CALL add_neighbor_list(points%sab_nl(1)%neighbor_list_set, atom, neighbors%neighbor_list)
452 CALL add_neighbor_node(neighbors%neighbor_list, neighbor, image, real(image, dp))
453 DO img = 1, 3
454 CALL dbcsr_create(source(1, img)%matrix, name="Image reconstruction", dist=distribution, &
455 matrix_type=matrix_type, row_blk_size=sizes, col_blk_size=sizes)
456 IF (comm%mepos == owner .AND. img == image(1) + 2) THEN
457 CALL dbcsr_put_block(source(1, img)%matrix, 1, 2, values)
458 END IF
459 CALL dbcsr_finalize(source(1, img)%matrix)
460 END DO
461 CALL dbcsr_create(cosine_matrix, name="Image cosine", dist=distribution, matrix_type=matrix_type, &
462 row_blk_size=sizes, col_blk_size=sizes)
463 CALL dbcsr_create(sine_matrix, name="Image sine", dist=distribution, matrix_type=mirror_type, &
464 row_blk_size=sizes, col_blk_size=sizes)
465 IF (comm%mepos == owner) THEN
466 CALL dbcsr_put_block(cosine_matrix, 1, 2, 0.0_dp*values)
467 CALL dbcsr_put_block(sine_matrix, 1, 2, 0.0_dp*values)
468 END IF
469 CALL dbcsr_finalize(cosine_matrix)
470 CALL dbcsr_finalize(sine_matrix)
471 expanded = 0.0_dp
472 CALL replicate_rs_matrices(source, points, expanded, points%cell_to_index)
473 DO ik = 1, 2
474 point = [0.137_dp, 0.217_dp, 0.089_dp]*real(ik - 1, dp)
475 CALL rs_to_kp(expanded(1, :, :, :), result, images, point)
476 phase = exp(gaussi*twopi*point(1))
477 expected = z_zero
478 expected(1:2, 3:5) = phase*values
479 expected(3:5, 1:2) = sign*conjg(transpose(expected(1:2, 3:5)))
480 IF (maxval(abs(result - expected)) > 1.e-12_dp) THEN
481 error stop "Image reconstruction depends on neighbor orientation"
482 END IF
483 CALL rskp_transform(cosine_matrix, sine_matrix, source, 1, point, &
484 points%cell_to_index, points%sab_nl)
485 CALL dbcsr_get_block_p(cosine_matrix, 1, 2, cosine, found)
486 IF (comm%mepos == owner .AND. .NOT. found) error stop "Missing image cosine block"
487 IF (found) THEN
488 CALL dbcsr_get_block_p(sine_matrix, 1, 2, sine, found)
489 IF (.NOT. found) error stop "Missing image sine block"
490 IF (maxval(abs(result(1:2, 3:5) - cmplx(cosine, sine, kind=dp))) > 1.e-12_dp) THEN
491 error stop "Image reconstruction differs from rskp_transform"
492 END IF
493 cosine = 0.0_dp
494 sine = 0.0_dp
495 END IF
496 END DO
497 CALL dbcsr_release(cosine_matrix)
498 CALL dbcsr_release(sine_matrix)
499 DO img = 1, 3
500 CALL dbcsr_release(source(1, img)%matrix)
501 END DO
502 CALL dbcsr_distribution_release(distribution)
503 CALL deallocate_neighbor_list_set(points%sab_nl(1)%neighbor_list_set)
504 END DO
505 END DO
506 DO img = 1, 3
507 DEALLOCATE (source(1, img)%matrix)
508 END DO
509 DEALLOCATE (points%cell_to_index, points%sab_nl)
510 DEALLOCATE (points, source, images)
511 DEALLOCATE (process_grid, row_dist, col_dist, sizes)
512 CALL dbcsr_finalize_lib()
514 CALL cp_logger_release(logger)
515 CALL mp_para_env_release(para_env)
516 END SUBROUTINE check_image_reconstruction
517
518! **************************************************************************************************
519!> \brief Apply the balanced two-level inverse used by the production local correction.
520!> \param inverse_k block-circulant base inverse
521!> \param lattice_dims replicated-cell dimensions
522!> \param correction_indices selected coordinate basis
523!> \param operator_columns columns A U
524!> \param coarse_inverse inverse of U^T A U
525!> \param input right-hand sides
526!> \param output corrected inverse action
527! **************************************************************************************************
528 SUBROUTINE apply_balanced_local_inverse(inverse_k, lattice_dims, correction_indices, &
529 operator_columns, coarse_inverse, input, output)
530
531 COMPLEX(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: inverse_k
532 INTEGER, DIMENSION(3), INTENT(IN) :: lattice_dims
533 INTEGER, DIMENSION(:), INTENT(IN) :: correction_indices
534 REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: operator_columns, coarse_inverse, input
535 REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: output
536
537 INTEGER :: i
538 LOGICAL :: used_fft
539 REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: base_input, coarse_input, &
540 coarse_projected, coarse_residual, &
541 coarse_rhs
542
543 ALLOCATE (base_input(SIZE(input, 1), SIZE(input, 2)), &
544 coarse_input(SIZE(correction_indices), SIZE(input, 2)), &
545 coarse_projected(SIZE(correction_indices), SIZE(input, 2)), &
546 coarse_residual(SIZE(correction_indices), SIZE(input, 2)), &
547 coarse_rhs(SIZE(correction_indices), SIZE(input, 2)))
548 DO i = 1, SIZE(correction_indices)
549 coarse_input(i, :) = input(correction_indices(i), :)
550 END DO
551 coarse_rhs(:, :) = matmul(coarse_inverse, coarse_input)
552 base_input(:, :) = input - matmul(operator_columns, coarse_rhs)
553 CALL apply_lattice_inverse_dense(inverse_k, lattice_dims, base_input, output, used_fft)
554 IF (.NOT. used_fft) error stop "Balanced correction base did not use lattice FFT"
555 coarse_projected(:, :) = matmul(transpose(operator_columns), output)
556 coarse_residual(:, :) = matmul(coarse_inverse, coarse_projected)
557 output(correction_indices, :) = output(correction_indices, :) + coarse_rhs - coarse_residual
558 DEALLOCATE (base_input, coarse_input, coarse_projected, coarse_residual, coarse_rhs)
559
560 END SUBROUTINE apply_balanced_local_inverse
561
562! **************************************************************************************************
563!> \brief ...
564!> \param values_rs ...
565!> \param index_to_cell ...
566!> \param xkp ...
567!> \param values_k ...
568!> \param deriv_direction ...
569!> \param hmat ...
570! **************************************************************************************************
571 SUBROUTINE direct_reference(values_rs, index_to_cell, xkp, values_k, deriv_direction, hmat)
572
573 REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: values_rs
574 INTEGER, DIMENSION(:, :), INTENT(IN) :: index_to_cell
575 REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp
576 COMPLEX(KIND=dp), DIMENSION(:, :, :), INTENT(OUT) :: values_k
577 INTEGER, INTENT(IN), OPTIONAL :: deriv_direction
578 REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN), &
579 OPTIONAL :: hmat
580
581 COMPLEX(KIND=dp) :: factor
582 INTEGER :: icell, ik
583 REAL(KIND=dp), DIMENSION(3) :: cell_index_real, cell_vector
584
585 values_k = z_zero
586 DO ik = 1, SIZE(xkp, 2)
587 DO icell = 1, SIZE(values_rs, 3)
588 factor = exp(gaussi*twopi*sum(xkp(:, ik)*real(index_to_cell(:, icell), kind=dp)))
589 IF (PRESENT(deriv_direction)) THEN
590 cell_index_real = real(index_to_cell(:, icell), kind=dp)
591 cell_vector = matmul(hmat, cell_index_real)
592 factor = factor*gaussi*cell_vector(deriv_direction)
593 END IF
594 values_k(:, :, ik) = values_k(:, :, ik) + factor*values_rs(:, :, icell)
595 END DO
596 END DO
597
598 END SUBROUTINE direct_reference
599
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
subroutine check_image_reconstruction(comm)
Check triangular image storage against rskp_transform for both neighbor orientations.
program kpoint_lattice_fft_unittest
Definition atom.F:9
subroutine, public dbcsr_distribution_release(dist)
...
subroutine, public dbcsr_distribution_new(dist, template, group, pgrid, row_dist, col_dist, reuse_arrays)
...
subroutine, public dbcsr_get_block_p(matrix, row, col, block, found, row_size, col_size)
...
subroutine, public dbcsr_finalize(matrix)
...
subroutine, public dbcsr_release(matrix)
...
subroutine, public dbcsr_put_block(matrix, row, col, block, summation)
...
various routines to log and control the output. The idea is that decisions about where to log should ...
subroutine, public cp_rm_default_logger()
the cousin of cp_add_default_logger, decrements the stack, so that the default logger is what it has ...
subroutine, public cp_logger_release(logger)
releases this logger
subroutine, public cp_logger_create(logger, para_env, print_level, default_global_unit_nr, default_local_unit_nr, global_filename, local_filename, close_global_unit_on_dealloc, iter_info, close_local_unit_on_dealloc, suffix, template_logger)
initializes a logger
subroutine, public cp_add_default_logger(logger)
adds a default logger. MUST be called before logging occours
subroutine, public finalize_fft(para_env, wisdom_file, export_wisdom)
does whatever is needed to finalize the current fft setup
Definition fft_tools.F:209
subroutine, public init_fft(fftlib, alltoall, pool_limit, wisdom_file, plan_style)
...
Definition fft_tools.F:181
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Implements simple k-space/R-space transformations and Gamma-point MIC reconstruction.
subroutine, public rs_to_kp(rs_real, ks_complex, index_to_cell, xkp, deriv_direction, hmat)
Integrate RS matrices (stored as Fortran array) into a kpoint matrix at given kp.
subroutine, public replicate_rs_matrices(rs_dbcsr_in, kpoint_in, rs_array_out, cell_to_index_out)
Convert dbcsr matrices representing operators in real-space image cells to arrays.
Batched lattice Fourier transforms on regular k-point grids.
subroutine, public k_grid_to_cell_prepare(work, xkp, nkp_grid, index_to_cell, weights, allow_incomplete)
Prepare one inverse lattice transform for repeated matrix batches.
logical function, public regular_kpoint_grid(xkp, nkp_grid, grid_index, k_offset, allow_incomplete)
Test and map a uniformly shifted reciprocal grid or an explicitly allowed subset.
subroutine, public k_grid_to_cell_execute(work, values_k, values_rs, used_fft)
Execute a matrix batch using the prepared inverse lattice transform. Call outside OpenMP worker regio...
subroutine, public k_grid_to_cell_release(work)
Release call-scoped inverse lattice maps and FFT buffers.
subroutine, public cell_to_k_grid_fft(values_rs, index_to_cell, xkp, nkp_grid, values_k, used_fft, deriv_direction, hmat, selected_kpoints)
Transform a batch of real matrices from image cells to every supplied k point.
subroutine, public k_grid_to_cell_fft(values_k, xkp, nkp_grid, index_to_cell, values_rs, used_fft, weights, allow_incomplete)
Transform reciprocal-grid data back to image-cell values.
Routines needed for kpoint calculation.
subroutine, public rskp_transform(rmatrix, cmatrix, rsmat, ispin, xkp, cell_to_index, sab_nl, is_complex, rs_sign)
Transformation of real space matrices to a kpoint.
Types and basic routines needed for a kpoint calculation.
Block-circulant inverse operators for replicated-cell OT preconditioners.
subroutine, public build_lattice_local_correction(operator_matrix, lattice_dims, local_cell_count, correction_indices, operator_columns, coarse_inverse, corrected_projection_error, info)
Build a balanced local correction for selected non-circulant cell blocks.
subroutine, public apply_lattice_inverse_dense(inverse_k, lattice_dims, matrix_in, matrix_out, used_fft, imaginary_residual)
Apply inverse Fourier blocks to a dense cell-major real matrix.
subroutine, public apply_lattice_state_inverse_dense(inverse_k, lattice_dims, matrix_in, matrix_out, used_fft, imaginary_residual, state_indices)
Apply one inverse Fourier operator to every column of a dense real matrix.
subroutine, public build_lattice_inverse(operator_matrix, lattice_dims, inverse_k, projection_error, used_fft, info)
Project a cell-major SPD operator onto lattice translations and invert its Fourier blocks.
pure real(kind=dp) function, public lattice_local_storage_ratio(lattice_dims, operator_count, local_cell_count)
Estimate balanced-local-correction storage relative to one dense real operator.
pure real(kind=dp) function, public lattice_fft_storage_ratio(lattice_dims, operator_count)
Estimate reciprocal-block storage relative to one dense real operator.
pure logical function, public lattice_fft_auto_select(lattice_dims, block_size, rhs_count, operator_count, num_pe, projection_error, used_fft, info)
Conservative error-, work-, and storage-aware AUTO selector.
subroutine, public lattice_grid(lattice_dims, index_to_cell, xkp)
Enumerate a regular direct/reciprocal lattice with the first direction varying fastest.
pure real(kind=dp) function, public lattice_local_cost_ratio(lattice_dims, local_cell_count)
Estimate balanced-local-correction work relative to a dense inverse application.
pure real(kind=dp) function, public lattice_fft_cost_ratio(lattice_dims, block_size, rhs_count, num_pe)
Estimate lattice-FFT application work relative to a dense inverse application.
Machine interface based on Fortran 2003 and POSIX.
Definition machine.F:17
integer, parameter, public default_output_unit
Definition machine.F:48
Definition of mathematical constants and functions.
complex(kind=dp), parameter, public gaussi
real(kind=dp), parameter, public twopi
complex(kind=dp), parameter, public z_zero
Interface to the message passing library MPI.
subroutine, public mp_world_init(mp_comm)
initializes the system default communicator
subroutine, public mp_para_env_release(para_env)
releases the para object (to be called when you don't want anymore the shared copy of this object)
subroutine, public mp_world_finalize()
Finalize the system default communicator and MPI when CP2K owns MPI.
Define the neighbor list data types and the corresponding functionality.
subroutine, public deallocate_neighbor_list_set(neighbor_list_set)
Deallocate a neighbor list set.
subroutine, public add_neighbor_node(neighbor_list, neighbor, cell, r, exclusion_list, nkind)
Add a new neighbor list node to a neighbor list.
subroutine, public add_neighbor_list(neighbor_list_set, atom, neighbor_list)
Add a new neighbor list to a neighbor list set.
subroutine, public allocate_neighbor_list_set(neighbor_list_set, symmetric)
Allocate and initialize a set of neighbor lists.
type of a logger, at the moment it contains just a print level starting at which level it should be l...
Contains information about kpoints.
stores all the informations relevant to an mpi environment