(git:6344619)
Loading...
Searching...
No Matches
quadratic_pseudospectrum_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!--------------------------------------------------------------------------------------------------!
9#if defined(__HAS_IEEE_EXCEPTIONS)
10 USE ieee_exceptions, ONLY: ieee_all, ieee_get_halting_mode, ieee_set_halting_mode
11#endif
12 USE kinds, ONLY: dp
16
17 IMPLICIT NONE
18 COMPLEX(dp) :: op(2, 2, 4), s(2, 2), change(2, 2), rotated(2, 2, 4), metric(2, 2)
19 COMPLEX(dp), ALLOCATABLE :: defect(:, :, :), overlap(:, :), projected(:, :)
20 REAL(dp) :: shift(4), weights(4), expected, center
21 TYPE(quadratic_result_type) :: dense, iterative, transformed
22 INTEGER :: status, i, n, io_unit
23
24 CALL cp2k_init()
26 s = cmplx(0.0_dp, 0.0_dp, dp)
27 s(1, 1) = 1.0_dp
28 s(2, 2) = 1.0_dp
29 op = cmplx(0.0_dp, 0.0_dp, dp)
30 op(1, 1, 1) = 1.0_dp
31 op(2, 2, 1) = -1.0_dp
32 op(1, 2, 2) = cmplx(0.0_dp, 1.0_dp, dp)
33 op(2, 1, 2) = cmplx(0.0_dp, -1.0_dp, dp)
34 shift = [0.3_dp, 0.2_dp, 0.0_dp, 0.0_dp]
35 weights = [1.0_dp, 0.7_dp, 0.7_dp, 0.7_dp]
36 expected = 1.0_dp + shift(1)**2 + weights(2)**2*(1.0_dp + shift(2)**2) &
37 - 2.0_dp*sqrt(shift(1)**2 + weights(2)**4*shift(2)**2)
38 CALL quadratic_dense(op, s, shift, weights, 1, .false., 2, 200, 1.e-10_dp, 1.e-10_dp, dense, status)
39 IF (status /= 0) error stop 'Quadratic Pauli oracle failed'
40 IF (abs(dense%eigenvalues(1) - expected) > 1.e-12_dp) error stop 'Analytic quadratic eigenvalue mismatch'
41 CALL quadratic_dense(op, s, shift, weights, 1, .true., 2, 200, 1.e-10_dp, 1.e-10_dp, iterative, status)
42 IF (status /= 0) error stop 'Quadratic Pauli iteration failed'
43 IF (maxval(abs(dense%eigenvalues - iterative%eigenvalues)) > 1.e-12_dp) error stop 'Pauli Ritz mismatch'
44 change = reshape([cmplx(1.2_dp, 0.1_dp, dp), cmplx(0.15_dp, -0.1_dp, dp), &
45 cmplx(0.1_dp, 0.2_dp, dp), cmplx(0.8_dp, 0.0_dp, dp)], [2, 2])
46 metric = matmul(conjg(transpose(change)), change)
47 DO i = 1, 4
48 rotated(:, :, i) = matmul(conjg(transpose(change)), matmul(op(:, :, i), change))
49 END DO
50 CALL quadratic_dense(rotated, metric, shift, weights, 1, .false., 2, 200, 1.e-10_dp, 1.e-10_dp, &
51 transformed, status)
52 IF (status /= 0) error stop 'Nonorthogonal complex basis failed'
53 IF (maxval(abs(dense%eigenvalues - transformed%eigenvalues)) > 1.e-12_dp) error stop 'Basis covariance failed'
54 IF (maxval(abs(dense%errors - transformed%errors)) > 1.e-12_dp) error stop 'Observable residual covariance failed'
55 IF (maxval(abs(dense%means - transformed%means)) > 1.e-12_dp) error stop 'Observable mean covariance failed'
56 DO i = 1, 4
57 op(:, :, i) = op(:, :, i) + real(i, dp)*s
58 shift(i) = shift(i) + real(i, dp)
59 END DO
60 CALL quadratic_dense(op, s, shift, weights, 1, .false., 2, 200, 1.e-10_dp, 1.e-10_dp, transformed, status)
61 IF (status /= 0) error stop 'Shifted quadratic oracle failed'
62 IF (maxval(abs(dense%eigenvalues - transformed%eigenvalues)) > 1.e-12_dp) error stop 'Origin invariance failed'
63 IF (maxval(abs(dense%errors - transformed%errors)) > 1.e-12_dp) error stop 'Residual origin invariance failed'
64
65 n = 40
66 center = 20.0_dp
67 ALLOCATE (defect(n, n, 4), overlap(n, n), projected(3, 3))
68 defect = cmplx(0.0_dp, 0.0_dp, dp)
69 overlap = cmplx(0.0_dp, 0.0_dp, dp)
70 DO i = 1, n
71 overlap(i, i) = 1.0_dp
72 defect(i, i, 1) = 5.0_dp
73 defect(i, i, 2) = real(i, dp) - center
74 IF (i < n) THEN
75 defect(i, i + 1, 1) = cmplx(-0.1_dp, 0.02_dp, dp)
76 defect(i + 1, i, 1) = conjg(defect(i, i + 1, 1))
77 END IF
78 END DO
79 defect(20, 20, 1) = 0.0_dp
80 shift = 0.0_dp
81 weights = [1.0_dp, 0.2_dp, 0.2_dp, 0.2_dp]
82 CALL quadratic_dense(defect, overlap, shift, weights, 3, .false., n, 500, 1.e-9_dp, 1.e-10_dp, dense, status)
83 IF (status /= 0) error stop 'Defect oracle failed'
84 IF (abs(dense%states(20, 1))**2 < 0.95_dp) error stop 'Defect state not localized'
85 CALL quadratic_dense(defect, overlap, shift, weights, 3, .true., 20, 500, 1.e-9_dp, 1.e-10_dp, iterative, status)
86 IF (status /= 0) error stop 'Defect iteration failed'
87 IF (maxval(abs(dense%eigenvalues - iterative%eigenvalues)) > 1.e-8_dp) error stop 'Defect Ritz eigenvalue mismatch'
88 projected(:, :) = matmul(conjg(transpose(dense%states)), iterative%states)
89 IF (sum(abs(projected)**2) < 3.0_dp - 1.e-7_dp) error stop 'Defect invariant subspace mismatch'
90 CALL quadratic_dense(defect, overlap, shift, weights, 3, .true., 12, 1, 1.e-12_dp, 1.e-10_dp, iterative, status)
91 IF (status /= 1) error stop 'Unconverged quadratic solve accepted'
92 ! Exactly degenerate joint states: compare the projector, not individual eigenvectors.
93 defect = cmplx(0.0_dp, 0.0_dp, dp)
94 DO i = 1, n
95 defect(i, i, 1) = 2.0_dp
96 END DO
97 defect(19, 19, 1) = 0.0_dp
98 defect(20, 20, 1) = 0.0_dp
99 CALL quadratic_dense(defect, overlap, shift, weights, 2, .true., 8, 200, 1.e-10_dp, 1.e-10_dp, iterative, status)
100 IF (status /= 0) error stop 'Degenerate quadratic iteration failed'
101 IF (maxval(abs(iterative%eigenvalues)) > 1.e-12_dp) error stop 'Degenerate eigenvalues failed'
102 IF (abs(sum(abs(iterative%states(19:20, :))**2) - 2.0_dp) > 1.e-12_dp) error stop 'Degenerate projector failed'
103 overlap(1, 1) = -1.0_dp
104 CALL quadratic_dense(defect, overlap, shift, weights, 3, .false., n, 200, 1.e-9_dp, 1.e-10_dp, dense, status)
105 IF (status /= -2) error stop 'Indefinite metric accepted'
106 overlap(1, 1) = 1.e-14_dp
107 CALL quadratic_dense(defect, overlap, shift, weights, 3, .false., n, 200, 1.e-9_dp, 1.e-10_dp, dense, status)
108 IF (status /= -2) error stop 'Ill-conditioned metric accepted'
109 DEALLOCATE (defect, overlap, projected)
110 CALL periodic_tests()
111 CALL translation_tests()
112 CALL folded_translation_tests()
114 CALL cp2k_finalize()
115CONTAINS
116! **************************************************************************************************
117!> \brief Compression of a three-state unitary to two AOs retains the missing normal Gram exactly.
118! **************************************************************************************************
120 COMPLEX(dp) :: change(2, 2), changed(2, 2, 2), &
121 metric(2, 2), op(2, 2, 2), query(2), &
122 transformed(2, 2)
123 INTEGER :: i, status
124 REAL(dp) :: center, diagonal(2), err, expected(2), &
125 split, weights(2)
126 TYPE(quadratic_result_type) :: full, projected, rotated
127
128 metric = 0
129 metric(1, 1) = 1
130 metric(2, 2) = 1
131 op = 0
132 op(1, 1, 1) = 0.2_dp
133 op(2, 2, 1) = -0.4_dp
134 op(1, 2, 2) = 1
135 query = [cmplx(0.1_dp, 0.0_dp, dp), exp(cmplx(0.0_dp, 0.73_dp, dp))]
136 weights = [1.0_dp, 0.7_dp]
137 diagonal = [0.1_dp**2, 0.5_dp**2] + 2*weights(2)**2
138 center = sum(diagonal)/2
139 split = sqrt(((diagonal(1) - diagonal(2))/2)**2 + weights(2)**4)
140 expected = [center - split, center + split]
141 CALL quadratic_dense(op, metric, query, weights, 2, .false., 2, 100, 1.e-11_dp, 1.e-10_dp, &
142 full, status, unitary=[.false., .true.])
143 IF (status /= 0) error stop 'Compressed unitary solve failed'
144 err = maxval(abs(full%eigenvalues - expected))
145 IF (err > 1.e-12_dp) error stop 'Full translation normal Gram differs from analytic result'
146 IF (maxval(abs(full%errors**2 - full%projected_errors**2 - full%leakage**2)) > 1.e-12_dp) THEN
147 error stop 'Continuum/projected residual decomposition failed'
148 END IF
149 IF (maxval(abs(full%leakage(2, :)**2 - abs(full%states(1, :))**2)) > 1.e-12_dp) THEN
150 error stop 'Translation leakage differs from discarded ambient component'
151 END IF
152 CALL quadratic_dense(op, metric, query, weights, 2, .false., 2, 100, 1.e-11_dp, 1.e-10_dp, projected, status)
153 IF (status /= 0) error stop 'Projected unitary comparison failed'
154 IF (maxval(abs(projected%eigenvalues - full%eigenvalues)) < 0.1_dp) error stop 'Projection negative control failed'
155 change = reshape([cmplx(1.2_dp, 0.1_dp, dp), cmplx(0.15_dp, -0.1_dp, dp), &
156 cmplx(0.1_dp, 0.2_dp, dp), cmplx(0.8_dp, 0.0_dp, dp)], [2, 2])
157 transformed = matmul(conjg(transpose(change)), change)
158 DO i = 1, 2
159 changed(:, :, i) = matmul(conjg(transpose(change)), matmul(op(:, :, i), change))
160 END DO
161 CALL quadratic_dense(changed, transformed, query, weights, 2, .true., 2, 100, 1.e-11_dp, 1.e-10_dp, &
162 rotated, status, unitary=[.false., .true.])
163 IF (status /= 0) error stop 'Compressed unitary metric iteration failed'
164 IF (maxval(abs(rotated%eigenvalues - full%eigenvalues)) > 1.e-12_dp) error stop 'Unitary metric covariance failed'
165 IF (maxval(abs(rotated%leakage - full%leakage)) > 1.e-12_dp) error stop 'Leakage metric covariance failed'
166 op(:, :, 2) = 2*metric
167 CALL quadratic_dense(op, metric, query, weights, 2, .false., 2, 100, 1.e-11_dp, 1.e-10_dp, &
168 rotated, status, unitary=[.false., .true.])
169 IF (status /= -4) error stop 'Invalid expanding unitary compression accepted'
170 IF (io_unit > 0) WRITE (io_unit, '(A,ES15.6)') 'Compressed unitary full-normal analytic error: ', err
171 END SUBROUTINE compressed_translation_tests
172
173! **************************************************************************************************
174!> \brief A trimerized periodic chain must equal its independently assembled three-band Bloch blocks.
175! **************************************************************************************************
176 SUBROUTINE folded_translation_tests()
177 INTEGER, PARAMETER :: cells = 6, n = 3*cells
178
179 COMPLEX(dp) :: bloch(3, 3, 2), identity(3, 3), &
180 metric(n, n), operators(n, n, 2), &
181 phase, query(2)
182 INTEGER :: first, i, ie, ik, iq, j, loc, status
183 REAL(dp) :: energy(5), expected(n), hopping, &
184 joined(n), k, maximum_error, q, &
185 weights(2)
186 TYPE(quadratic_result_type) :: full, sector
187
188 operators = 0
189 metric = 0
190 identity = 0
191 DO i = 1, 3
192 identity(i, i) = 1
193 END DO
194 DO i = 1, n
195 metric(i, i) = 1
196 j = modulo(i, n) + 1
197 operators(i, j, 2) = 1
198 hopping = 0.8_dp
199 IF (modulo(i, 3) == 0) hopping = 1.2_dp
200 operators(i, j, 1) = -hopping
201 operators(j, i, 1) = -hopping
202 END DO
203 energy = [-2.2_dp, -1.0_dp, 0.0_dp, 0.7_dp, 2.0_dp]
204 weights = [1.0_dp, 0.7_dp]
205 maximum_error = 0
206 DO ik = 0, 12
207 k = -acos(-1.0_dp) + 2*acos(-1.0_dp)*real(ik, dp)/13
208 DO ie = 1, SIZE(energy)
209 query = [cmplx(energy(ie), 0.0_dp, dp), exp(cmplx(0.0_dp, k, dp))]
210 CALL quadratic_dense(operators, metric, query, weights, n, .false., n, 100, &
211 1.e-10_dp, 1.e-10_dp, full, status)
212 IF (status /= 0) error stop 'Full trimerized quadratic scan failed'
213 DO iq = 0, cells - 1
214 q = 2*acos(-1.0_dp)*real(iq, dp)/cells
215 phase = exp(cmplx(0.0_dp, q, dp))
216 bloch = 0
217 bloch(1, 2, 2) = 1
218 bloch(2, 3, 2) = 1
219 bloch(3, 1, 2) = phase
220 bloch(1, 2, 1) = -0.8_dp
221 bloch(2, 3, 1) = -0.8_dp
222 bloch(3, 1, 1) = -1.2_dp*phase
223 bloch(:, :, 1) = bloch(:, :, 1) + conjg(transpose(bloch(:, :, 1)))
224 CALL quadratic_dense(bloch, identity, query, weights, 3, .false., 3, 100, &
225 1.e-10_dp, 1.e-10_dp, sector, status)
226 IF (status /= 0) error stop 'Bloch-block quadratic scan failed'
227 first = 3*iq + 1
228 joined(first:first + 2) = sector%eigenvalues
229 END DO
230 DO i = 1, n
231 loc = minloc(joined, dim=1)
232 expected(i) = joined(loc)
233 joined(loc) = huge(1.0_dp)
234 END DO
235 maximum_error = max(maximum_error, maxval(abs(full%eigenvalues - expected)))
236 END DO
237 END DO
238 IF (maximum_error > 1.e-11_dp) error stop 'Full/Bloch trimerized quadratic spectra differ'
239 IF (io_unit > 0) WRITE (io_unit, '(A,I0,A,ES15.6)') 'Trimerized full/Bloch spectra: ', 13*SIZE(energy)*n, &
240 ' eigenvalues; maximum error ', maximum_error
241 END SUBROUTINE folded_translation_tests
242
243! **************************************************************************************************
244!> \brief Exact Bloch phases, nonnormal open translations and an independent generalized Gram oracle.
245! **************************************************************************************************
246 SUBROUTINE translation_tests()
247 INTEGER, PARAMETER :: n = 18
248
249 COMPLEX(dp) :: changed(n, n, 2), identity(n, n), metric(n, n), offset(2), &
250 operators(n, n, 2), projector(n, n), query(2), split(n, n, 3), transform(n, n)
251 INTEGER :: i, j, status
252 REAL(dp) :: covariance_error, expected(n), &
253 gap_error, hopping, mean_error, &
254 nonnormal_error, phase, weights(2)
255 TYPE(quadratic_result_type) :: altered, incorrect, iterative, original
256
257 identity = 0
258 operators = 0
259 DO i = 1, n
260 identity(i, i) = 1
261 operators(i, modulo(i, n) + 1, 2) = 1
262 END DO
263 operators(:, :, 1) = -operators(:, :, 2) - conjg(transpose(operators(:, :, 2)))
264 phase = 2*acos(-1.0_dp)*5/real(n, dp)
265 query = [cmplx(-2*cos(phase) + 0.031_dp, 0.0_dp, dp), exp(cmplx(0.0_dp, phase, dp))]
266 weights = [1.0_dp, 1.3_dp]
267 CALL quadratic_dense(operators, identity, query, weights, 1, .false., n, 200, &
268 1.e-10_dp, 1.e-10_dp, original, status)
269 IF (status /= 0) error stop 'Unitary translation quadratic solve failed'
270 IF (abs(original%eigenvalues(1) - 0.031_dp**2) > 1.e-12_dp) error stop 'Exact Bloch energy/phase failed'
271 IF (abs(original%complex_means(2, 1) - query(2)) > 1.e-12_dp) error stop 'Bloch translation mean lost phase'
272 IF (original%errors(2, 1) > 1.e-12_dp) error stop 'Bloch translation residual failed'
273 CALL quadratic_dense(operators, identity, real(query, dp), weights, 1, .false., n, 200, &
274 1.e-10_dp, 1.e-10_dp, altered, status)
275 IF (status /= -1) error stop 'Hermitian interface accepted non-Hermitian translation'
276
277 ! The truncated translation is nonnormal. Its adjoint cannot be replaced by itself
278 ! or by an independent sum of squares of its Hermitian real/imaginary parts.
279 operators(n, 1, 2) = 0
280 operators(:, :, 1) = 0
281 DO i = 1, n - 1
282 hopping = 0.8_dp
283 IF (modulo(i, 3) == 0) hopping = 1.2_dp
284 operators(i, i + 1, 1) = -hopping
285 operators(i + 1, i, 1) = -hopping
286 END DO
287 operators(4, 4, 1) = 0.17_dp
288 query = [cmplx(0.33_dp, 0.0_dp, dp), exp(cmplx(0.0_dp, 0.73_dp, dp))]
289 CALL quadratic_dense(operators, identity, query, weights, n, .false., n, 200, &
290 1.e-10_dp, 1.e-10_dp, original, status)
291 IF (status /= 0) error stop 'Open trimerized translation solve failed'
292 CALL gram_reference(operators, identity, query, weights, expected)
293 gap_error = maxval(abs(original%eigenvalues - expected))
294 IF (gap_error > 1.e-11_dp) error stop 'General quadratic Gram oracle mismatch'
295 CALL quadratic_dense(operators, identity, query, weights, 2, .true., 10, 2000, &
296 1.e-10_dp, 1.e-10_dp, iterative, status)
297 IF (status /= 0) error stop 'Nonnormal restarted iteration failed'
298 IF (maxval(abs(iterative%eigenvalues - expected(:2))) > 1.e-10_dp) error stop 'Nonnormal Ritz spectrum mismatch'
299 projector = matmul(iterative%states, conjg(transpose(iterative%states))) - &
300 matmul(original%states(:, :2), conjg(transpose(original%states(:, :2))))
301 IF (maxval(abs(projector)) > 1.e-8_dp) error stop 'Nonnormal invariant-subspace mismatch'
302 split(:, :, 1) = operators(:, :, 1)
303 split(:, :, 2) = 0.5_dp*(operators(:, :, 2) + conjg(transpose(operators(:, :, 2))))
304 split(:, :, 3) = cmplx(0.0_dp, -0.5_dp, dp)*(operators(:, :, 2) - conjg(transpose(operators(:, :, 2))))
305 CALL quadratic_dense(split, identity, [real(query(1), dp), real(query(2), dp), aimag(query(2))], &
306 [weights(1), weights(2), weights(2)], n, .false., n, 200, &
307 1.e-10_dp, 1.e-10_dp, incorrect, status)
308 IF (status /= 0) error stop 'Hermitian-split comparison solve failed'
309 nonnormal_error = maxval(abs(original%eigenvalues - incorrect%eigenvalues))
310 IF (nonnormal_error < 0.01_dp) error stop 'Open-translation counterexample lost nonnormality'
311
312 transform = identity
313 DO i = 1, n - 1
314 transform(i, i) = 1 + 0.02_dp*i
315 transform(i, i + 1) = cmplx(0.21_dp, -0.12_dp, dp)
316 END DO
317 metric = matmul(conjg(transpose(transform)), transform)
318 DO j = 1, 2
319 changed(:, :, j) = matmul(conjg(transpose(transform)), matmul(operators(:, :, j), transform))
320 END DO
321 CALL quadratic_dense(changed, metric, query, weights, n, .false., n, 200, &
322 1.e-10_dp, 1.e-10_dp, altered, status)
323 IF (status /= 0) error stop 'Nonnormal complex AO basis failed'
324 CALL gram_reference(changed, metric, query, weights, expected)
325 covariance_error = maxval(abs(original%eigenvalues - altered%eigenvalues))
326 IF (covariance_error > 1.e-11_dp) error stop 'Nonnormal metric covariance failed'
327 IF (maxval(abs(altered%eigenvalues - expected)) > 1.e-11_dp) error stop 'Nonorthogonal Gram oracle mismatch'
328 mean_error = maxval(abs(original%complex_means - altered%complex_means))
329 IF (mean_error > 1.e-10_dp) error stop 'Complex expectation covariance failed'
330 IF (maxval(abs(original%errors - altered%errors)) > 1.e-10_dp) error stop 'Complex residual covariance failed'
331 offset = [cmplx(0.21_dp, -0.12_dp, dp), cmplx(-0.43_dp, 0.31_dp, dp)]
332 DO j = 1, 2
333 changed(:, :, j) = changed(:, :, j) + offset(j)*metric
334 END DO
335 CALL quadratic_dense(changed, metric, query + offset, weights, n, .false., n, 200, &
336 1.e-10_dp, 1.e-10_dp, altered, status)
337 IF (status /= 0) error stop 'Complex operator/query origin solve failed'
338 IF (maxval(abs(original%eigenvalues - altered%eigenvalues)) > 1.e-11_dp) error stop 'Complex origin covariance failed'
339 DO j = 1, 2
340 IF (maxval(abs(altered%complex_means(j, :) - original%complex_means(j, :) - offset(j))) > 1.e-10_dp) THEN
341 error stop 'Complex expectation origin covariance failed'
342 END IF
343 END DO
344 IF (io_unit > 0) WRITE (io_unit, '(A,4ES15.6)') 'Translation Gram/metric/complex-mean/split-error: ', &
345 gap_error, covariance_error, mean_error, nonnormal_error
346 changed(:, :, 1) = matmul(conjg(transpose(transform)), matmul(operators(:, :, 1), transform))
347 changed(:, :, 2) = metric
348 query(2) = 1
349 CALL quadratic_dense(changed, metric, query, weights, 2, .true., 10, 2000, &
350 1.e-10_dp, 1.e-10_dp, iterative, status, unitary=[.false., .true.])
351 IF (status /= 0) error stop 'Restarted identity translation failed'
352 IF (iterative%iterations < 2) error stop 'Identity translation did not exercise restarts'
353 IF (maxval(iterative%errors(2, :)) > 5.e-8_dp) error stop 'Identity full residual exceeds roundoff'
354 IF (maxval(iterative%projected_errors(2, :)) > 1.e-12_dp) error stop 'Identity projected residual drift'
355 IF (maxval(iterative%leakage(2, :)) > 5.e-8_dp) error stop 'Identity projection leakage exceeds roundoff'
356 END SUBROUTINE translation_tests
357
358! **************************************************************************************************
359!> \brief Independent explicit normal-product reference using LU solves and a generalized eigensolve.
360!> \param operators Covariant operators
361!> \param metric Positive AO overlap
362!> \param query Complex operator queries
363!> \param weights Nonnegative residual scales
364!> \param values Complete ascending generalized spectrum
365! **************************************************************************************************
366 SUBROUTINE gram_reference(operators, metric, query, weights, values)
367 COMPLEX(dp), INTENT(IN) :: operators(:, :, :), metric(:, :), query(:)
368 REAL(dp), INTENT(IN) :: weights(:)
369 REAL(dp), INTENT(OUT) :: values(:)
370 COMPLEX(dp), ALLOCATABLE :: gram(:, :), shifted(:, :), solved(:, :), lu(:, :), work(:)
371 REAL(dp), ALLOCATABLE :: rwork(:)
372 INTEGER, ALLOCATABLE :: pivots(:)
373 INTEGER :: n, i, status
374#if defined(__HAS_IEEE_EXCEPTIONS)
375 LOGICAL :: halt(SIZE(IEEE_ALL))
376#endif
377
378 n = SIZE(metric, 1)
379 ALLOCATE (gram(n, n), shifted(n, n), solved(n, n), lu(n, n), pivots(n), work(4*n), rwork(4*n))
380 gram = 0
381 DO i = 1, SIZE(query)
382 lu(:, :) = metric
383 shifted(:, :) = operators(:, :, i) - query(i)*metric
384 solved(:, :) = shifted
385#if defined(__HAS_IEEE_EXCEPTIONS)
386 CALL ieee_get_halting_mode(ieee_all, halt)
387 CALL ieee_set_halting_mode(ieee_all, .false.)
388#endif
389 CALL zgesv(n, n, lu, n, pivots, solved, n, status)
390#if defined(__HAS_IEEE_EXCEPTIONS)
391 CALL ieee_set_halting_mode(ieee_all, halt)
392#endif
393 IF (status /= 0) error stop 'Explicit Gram metric solve failed'
394 gram(:, :) = gram + weights(i)**2*matmul(conjg(transpose(shifted)), solved)
395 END DO
396 IF (maxval(abs(gram - conjg(transpose(gram)))) > 1.e-11_dp) error stop 'Explicit Gram is not Hermitian'
397 lu(:, :) = metric
398#if defined(__HAS_IEEE_EXCEPTIONS)
399 CALL ieee_get_halting_mode(ieee_all, halt)
400 CALL ieee_set_halting_mode(ieee_all, .false.)
401#endif
402 CALL zhegv(1, 'N', 'L', n, gram, n, lu, n, values, work, SIZE(work), rwork, status)
403#if defined(__HAS_IEEE_EXCEPTIONS)
404 CALL ieee_set_halting_mode(ieee_all, halt)
405#endif
406 IF (status /= 0) error stop 'Explicit generalized Gram spectrum failed'
407 END SUBROUTINE gram_reference
408
409! **************************************************************************************************
410!> \brief Three-dimensional trigonometric coordinates, basis covariance and torus-query invariance.
411! **************************************************************************************************
412 SUBROUTINE periodic_tests()
413 INTEGER, PARAMETER :: n = 8
414
415 COMPLEX(dp) :: changed(n, n, 7), identity(n, n), &
416 metric(n, n), operators(n, n, 7), &
417 transform(n, n)
418 INTEGER :: i, j, k, status
419 REAL(dp) :: diagonal(n), expected(n), move(3), &
420 radius(3), shift(7), theta(3), value, &
421 weights(7)
422 TYPE(quadratic_result_type) :: altered, iterative, original
423
424 identity = 0
425 operators = 0
426 theta = [0.21_dp, -0.37_dp, 1.43_dp]
427 radius = [0.7_dp, 1.2_dp, 0.9_dp]
428 shift(1) = 0.73_dp
429 weights(1) = 1
430 DO j = 1, 3
431 shift(2*j:2*j + 1) = [cos(theta(j)), sin(theta(j))]
432 weights(2*j:2*j + 1) = radius(j)
433 END DO
434 DO i = 1, n
435 identity(i, i) = 1
436 operators(i, i, 1) = 0.2_dp*i
437 DO j = 1, 3
438 value = 2*acos(-1.0_dp)*modulo(real(i*(2*j - 1), dp)/real(n + j, dp), 1.0_dp)
439 operators(i, i, 2*j) = cos(value)
440 operators(i, i, 2*j + 1) = sin(value)
441 END DO
442 diagonal(i) = sum((weights*abs(operators(i, i, :) - shift))**2)
443 END DO
444 DO i = 1, n
445 k = minloc(diagonal, dim=1)
446 expected(i) = diagonal(k)
447 diagonal(k) = huge(1.0_dp)
448 END DO
449 CALL quadratic_dense(operators, identity, shift, weights, n, .false., n, 100, 1.e-10_dp, 1.e-10_dp, original, status)
450 IF (status /= 0) error stop 'Periodic quadratic diagonal oracle failed'
451 IF (maxval(abs(original%eigenvalues - expected)) > 1.e-12_dp) error stop 'Seven-observable analytic spectrum failed'
452 DO i = 1, n - 1
453 operators(i, i + 1, 1) = cmplx(-0.12_dp, 0.04_dp, dp)
454 operators(i + 1, i, 1) = conjg(operators(i, i + 1, 1))
455 END DO
456 ! The six initial vectors leave only one or two slots for the three-vector residual block.
457 DO k = n - 1, n
458 CALL quadratic_dense(operators(:k, :k, :), identity(:k, :k), shift, weights, 3, .false., k, 100, &
459 1.e-10_dp, 1.e-10_dp, original, status)
460 IF (status /= 0) error stop 'Partial residual block reference failed'
461 CALL quadratic_dense(operators(:k, :k, :), identity(:k, :k), shift, weights, 3, .true., k, 2, &
462 1.e-10_dp, 1.e-10_dp, iterative, status)
463 IF (status /= 0) error stop 'Partial residual block did not fill the available space'
464 IF (iterative%iterations /= 2) error stop 'Partial residual block iteration count mismatch'
465 IF (maxval(abs(original%eigenvalues - iterative%eigenvalues)) > 1.e-12_dp) THEN
466 error stop 'Partial residual block eigenvalue mismatch'
467 END IF
468 END DO
469 ! Reuse the full-size reference from the final partial-residual-block check.
470 transform = identity
471 DO i = 1, n - 1
472 transform(i, i + 1) = cmplx(0.13_dp, -0.08_dp, dp)
473 END DO
474 metric = matmul(conjg(transpose(transform)), transform)
475 DO j = 1, 7
476 changed(:, :, j) = matmul(conjg(transpose(transform)), matmul(operators(:, :, j), transform))
477 END DO
478 CALL quadratic_dense(changed, metric, shift, weights, 3, .false., n, 100, 1.e-10_dp, 1.e-10_dp, altered, status)
479 IF (status /= 0) error stop 'Periodic complex metric failed'
480 IF (maxval(abs(original%eigenvalues - altered%eigenvalues)) > 1.e-12_dp) error stop 'Periodic metric covariance failed'
481 CALL quadratic_dense(changed, metric, shift, weights, 3, .true., n, 2, 1.e-10_dp, 1.e-10_dp, iterative, status)
482 IF (status /= 0) error stop 'Partial residual block with complex metric failed'
483 IF (maxval(abs(altered%eigenvalues - iterative%eigenvalues)) > 1.e-12_dp) THEN
484 error stop 'Partial residual block metric covariance failed'
485 END IF
486 move = [0.43_dp, -0.67_dp, 0.31_dp]
487 changed = operators
488 DO j = 1, 3
489 changed(:, :, 2*j) = cos(move(j))*operators(:, :, 2*j) - sin(move(j))*operators(:, :, 2*j + 1)
490 changed(:, :, 2*j + 1) = sin(move(j))*operators(:, :, 2*j) + cos(move(j))*operators(:, :, 2*j + 1)
491 shift(2*j:2*j + 1) = [cos(theta(j) + move(j)), sin(theta(j) + move(j))]
492 END DO
493 CALL quadratic_dense(changed, identity, shift, weights, 3, .false., n, 100, 1.e-10_dp, 1.e-10_dp, altered, status)
494 IF (status /= 0) error stop 'Shifted periodic coordinates failed'
495 IF (maxval(abs(original%eigenvalues - altered%eigenvalues)) > 1.e-12_dp) error stop 'Periodic coordinate-origin covariance failed'
496 DO j = 1, 3
497 value = theta(j) + 2*acos(-1.0_dp)*(j - 2)
498 shift(2*j:2*j + 1) = [cos(value), sin(value)]
499 END DO
500 CALL quadratic_dense(operators, identity, shift, weights, 3, .false., n, 100, 1.e-10_dp, 1.e-10_dp, altered, status)
501 IF (status /= 0) error stop 'Periodic query wrapping failed'
502 IF (maxval(abs(original%eigenvalues - altered%eigenvalues)) > 1.e-12_dp) error stop 'Periodic query invariance failed'
503 CALL quadratic_dense(operators, identity, shift, weights(:6), 1, .false., n, 100, 1.e-10_dp, 1.e-10_dp, altered, status)
504 IF (status /= -1) error stop 'Mismatched observable weights accepted'
505 CALL quadratic_dense(operators(:, :, :0), identity, shift(:0), weights(:0), 1, .false., n, 100, &
506 1.e-10_dp, 1.e-10_dp, altered, status)
507 IF (status /= -1) error stop 'Empty observable tuple accepted'
508 IF (io_unit > 0) WRITE (io_unit, *) 'Periodic quadratic tuple, metric, iteration and origin checks passed.'
509 END SUBROUTINE periodic_tests
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
CP2K C/C++ interface.
Definition libcp2k.F:20
subroutine, public cp2k_finalize()
...
Definition libcp2k.F:139
subroutine, public cp2k_init()
...
Definition libcp2k.F:104
Metric-aware quadratic pseudospectra for finite AO operators.
program quadratic_pseudospectrum_unittest
subroutine compressed_translation_tests()
Compression of a three-state unitary to two AOs retains the missing normal Gram exactly.