21#if defined(__HAS_IEEE_EXCEPTIONS)
22 USE ieee_exceptions,
ONLY: ieee_all, ieee_get_halting_mode
32#if defined(__HAS_IEEE_EXCEPTIONS)
33 LOGICAL :: original_halt(size(ieee_all)), current_halt(size(ieee_all))
35 COMPLEX(KIND=dp),
ALLOCATABLE :: h(:, :), s(:, :), r(:, :, :), transform(:, :), &
36 hc(:, :), sc(:, :), rc(:, :, :), hs(:, :), ss(:, :), rs(:, :, :)
37 INTEGER :: axis, i, index, reference, status, n, pf, permutation(4), io
38 REAL(kind=
dp) :: gap, gap_reference, ratio, skew(4, 4), exact
41#if defined(__HAS_IEEE_EXCEPTIONS)
42 CALL ieee_get_halting_mode(ieee_all, original_halt)
45 CALL real_inertia_tests()
47 CALL pfaffian_orientation_tests()
49 CALL aii_roundoff_tests()
59 skew = skew - transpose(skew)
60 exact = skew(1, 2)*skew(3, 4) - skew(1, 3)*skew(2, 4) + skew(1, 4)*skew(2, 3)
62 IF (status /= 0 .OR. pf /= int(sign(1.0_dp, exact))) error stop
'Pfaffian polynomial failed'
63 permutation = [2, 1, 3, 4]
65 IF (status /= 0 .OR. pf /= -int(sign(1.0_dp, exact))) error stop
'Pfaffian orientation failed'
68 IF (status == 0 .OR. pf /= 0) error stop
'Singular Pfaffian accepted'
70 ALLOCATE (h(1, 1), s(1, 1), r(1, 1, 2))
73 r(1, 1, :) = [6.0_dp, 8.0_dp]
74 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp], 1.0_dp, 0.2_dp, .false., index, gap, status)
75 IF (status /= 0 .OR. index /= 0 .OR. abs(gap - sqrt(2.0_dp)) > 1.e-12_dp)
THEN
76 error stop
'Analytic generalized localizer failed'
78 CALL evaluate(h, s, r, [3.0_dp, 4.0_dp], 2.0_dp, 0.2_dp, .false., index, gap, status)
79 IF (status /= 1) error stop
'Zero gap was assigned an index'
82 ALLOCATE (h(2, 2), s(2, 2), r(2, 2, 2))
90 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.2_dp, .false., index, gap, status)
91 IF (status /= 1) error stop
'Metric-amplified roundoff ignored'
94 CALL qwz_model(7, -1.0_dp, h, s, r)
96 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., reference, gap_reference, status)
97 IF (status /= 0 .OR. reference /= -1 .OR. abs(gap_reference - 0.740327333453389_dp) > 1.e-11_dp)
THEN
98 error stop
'Nontrivial open QWZ model failed'
100 CALL evaluate(h, s, r(:, :, [2, 1]), [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
101 IF (status /= 0 .OR. index /= -reference .OR. abs(gap - gap_reference) > 1.e-11_dp)
THEN
102 error stop
'Oriented-plane reversal failed'
104 CALL evaluate(conjg(h), s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
105 IF (status /= 0 .OR. index /= -reference) error stop
'Time reversed Chern sign failed'
106 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.15_dp, .false., index, gap, status)
107 IF (status /= 0 .OR. index /= reference) error stop
'Kappa plateau failed'
108 CALL evaluate(h, s, r, [20.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
109 IF (status /= 0 .OR. index /= 0) error stop
'Outside-vacuum limit failed'
111 ALLOCATE (transform(n, n), hc(n, n), sc(n, n), rc(n, n, 2))
114 transform(i, i) = (1.0_dp + real(mod(i, 5),
dp)/5.0_dp)*exp(cmplx(0.0_dp, 0.17_dp*i,
dp))
115 IF (i < n) transform(i, i + 1) = cmplx(0.05_dp, 0.03_dp,
dp)
117 hc(:, :) = matmul(conjg(transpose(transform)), matmul(h, transform))
118 sc(:, :) = matmul(conjg(transpose(transform)), matmul(s, transform))
120 rc(:, :, axis) = matmul(conjg(transpose(transform)), matmul(r(:, :, axis), transform))
122 CALL evaluate(hc, sc, rc, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
123 IF (status /= 0 .OR. index /= reference .OR. abs(gap - gap_reference) > 1.e-11_dp)
THEN
124 error stop
'Complex nonorthogonal basis invariance failed'
126 rc(:, :, 1) = rc(:, :, 1) + 13.0_dp*sc
127 rc(:, :, 2) = rc(:, :, 2) - 7.0_dp*sc
128 hc(:, :) = hc + 11.0_dp*sc
129 CALL evaluate(hc, sc, rc, [13.0_dp, -7.0_dp], 11.0_dp, 0.25_dp, .false., index, gap, status)
130 IF (status /= 0 .OR. index /= reference .OR. abs(gap - gap_reference) > 1.e-11_dp)
THEN
131 error stop
'Origin/energy shift covariance failed'
138 CALL evaluate(hc, sc, rc, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
139 IF (status /= -2) error stop
'Ill-conditioned metric accepted'
141 CALL evaluate(hc, sc, rc, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
142 IF (status /= -2) error stop
'Indefinite metric accepted'
143 hc(1, 2) = hc(1, 2) + 1.0_dp
144 CALL evaluate(hc, s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
145 IF (status /= -1) error stop
'Non-Hermitian Hamiltonian accepted'
148 ALLOCATE (hs(2*n, 2*n), ss(2*n, 2*n), rs(2*n, 2*n, 2))
153 hs(n + 1:, n + 1:) = conjg(h)
155 ss(n + 1:, n + 1:) = s
157 rs(n + 1:, n + 1:, :) = r
159 hs(i, n + i + 1) = 0.1_dp
160 hs(i + 1, n + i) = -0.1_dp
162 hs(n + 1:, :n) = conjg(transpose(hs(:n, n + 1:)))
163 CALL evaluate(hs, ss, rs, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .true., index, gap, status)
164 IF (status /= 0 .OR. index /= 1) error stop
'Spin-mixed nontrivial AII model failed'
167 transform = real(transform,
dp)
169 transform(i, i) = 1.0_dp + real(mod(i, 5),
dp)/5.0_dp
173 hs((i - 1)*n + 1:i*n, (axis - 1)*n + 1:axis*n) = &
174 matmul(transpose(transform), matmul(hs((i - 1)*n + 1:i*n, (axis - 1)*n + 1:axis*n), transform))
177 sc(:, :) = matmul(transpose(transform), matmul(s, transform))
179 ss(n + 1:, n + 1:) = sc
181 rc(:, :, axis) = matmul(transpose(transform), matmul(r(:, :, axis), transform))
182 rs(:n, :n, axis) = rc(:, :, axis)
183 rs(n + 1:, n + 1:, axis) = rc(:, :, axis)
185 CALL evaluate(hs, ss, rs, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .true., index, gap, status)
186 IF (status /= 0 .OR. index /= 1 .OR. abs(gap - gap_reference) > 1.e-11_dp)
THEN
187 error stop
'AII metric covariance failed'
189 hs(1, 1) = hs(1, 1) + 1.e-12_dp
190 CALL evaluate(hs, ss, rs, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .true., index, gap, status)
191 IF (status /= 0 .OR. index /= 1) error stop
'Roundoff-level AII residual failed'
192 hs(1, 1) = hs(1, 1) + 1.0_dp
193 CALL evaluate(hs, ss, rs, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .true., index, gap, status)
194 IF (status /= -3) error stop
'Broken physical time reversal accepted'
196 CALL evaluate(hs, ss, rs, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .true., index, gap, status)
197 IF (status /= 0 .OR. index /= 0) error stop
'Atomic AII calibration failed'
200 CALL qwz_model(7, -3.0_dp, h, s, r)
201 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp], 0.0_dp, 0.25_dp, .false., index, gap, status)
202 IF (status /= 0 .OR. index /= 0) error stop
'Trivial QWZ model failed'
203#if defined(__HAS_IEEE_EXCEPTIONS)
204 CALL ieee_get_halting_mode(ieee_all, current_halt)
205 IF (any(current_halt .NEQV. original_halt)) error stop
'Caller floating-point traps changed'
214 COMPLEX(dp),
ALLOCATABLE :: matrix(:, :), q(:, :), reference(:, :)
215 INTEGER :: i, j, m, n, status
216 REAL(dp) :: error, largest, residual
217 REAL(dp),
ALLOCATABLE :: actual(:, :), expected(:, :)
222 ALLOCATE (q(m, m), matrix(m, m), reference(m, m), expected(m, m), actual(m, m))
227 expected(i, j) = sin(real(i + 2*j, dp)) + cos(real(3*i - j, dp))
230 expected(:, :) = expected - transpose(expected)
232 q(i, 3*n + i) = cmplx(0.0_dp, -1.0_dp, dp)
233 q(n + i, 2*n + i) = cmplx(0.0_dp, 1.0_dp, dp)
234 q(2*n + i, n + i) = cmplx(0.0_dp, 1.0_dp, dp)
235 q(3*n + i, i) = cmplx(0.0_dp, -1.0_dp, dp)
238 matrix(:, :) = cmplx(0.0_dp, -1.0_dp, dp)*matmul(q, matmul(expected, conjg(transpose(q))))
239 reference(:, :) = matmul(conjg(transpose(q)), matmul(matrix, q))
241 error = max(maxval(abs(actual - expected)), maxval(abs(actual + aimag(reference))))
242 IF (status /= 0 .OR. error > 1.e-13_dp) error stop
'AII sparse-unitary transform failed'
243 largest = max(largest, error)
245 matrix(i, i) = matrix(i, i) - cmplx(0.0_dp, 5.e-12_dp, dp)
248 IF (status /= 0 .OR. maxval(abs(actual - expected)) > 1.e-13_dp .OR. residual < 4.9e-12_dp)
THEN
249 error stop
'AII skew projection or discarded-error bound failed'
251 IF (maxval(abs(actual + transpose(actual))) /= 0.0_dp) error stop
'AII projection is not exactly skew'
253 matrix(i, i) = matrix(i, i) + cmplx(0.0_dp, 5.e-12_dp, dp)
255 matrix(1, 1) = matrix(1, 1) + 0.1_dp
257 IF (status == 0) error stop
'Broken AII transform accepted'
259 IF (status == 0) error stop
'Invalid AII dimensions accepted'
260 DEALLOCATE (q, matrix, reference, expected, actual)
262 IF (io > 0)
WRITE (io,
'(A,ES14.5)')
'AII signed-permutation maximum error: ', largest
268 SUBROUTINE aii_roundoff_tests()
269 COMPLEX(dp) :: h0(4, 4), r0(4, 4, 2), s0(4, 4)
270 INTEGER :: i, index, status
278 h0(i, i) = real(3*mod(i + 1, 2) - 1, dp)
282 CALL evaluate(h0, s0, r0, [0.0_dp, 0.0_dp], 0.0_dp, 0.2_dp, .true., index, gap, status)
283 IF (status /= 0 .OR. index /= 0 .OR. abs(gap - 1.0_dp) > 1.e-12_dp) error stop
'AII roundoff rejected'
284 h0(1, 1) = -1.e-10_dp
285 h0(3, 3) = -1.e-10_dp
286 CALL evaluate(h0, s0, r0, [0.0_dp, 0.0_dp], 0.0_dp, 0.2_dp, .true., index, gap, status)
287 IF (status /= 1) error stop
'AII unresolved gap assigned an index'
289 CALL evaluate(h0, s0, r0, [0.0_dp, 0.0_dp], 0.0_dp, 0.2_dp, .true., index, gap, status)
290 IF (status /= -1) error stop
'AII non-Hermitian input projected away'
291 END SUBROUTINE aii_roundoff_tests
296 SUBROUTINE periodic_tests()
297 INTEGER,
PARAMETER :: length = 8
299 COMPLEX(dp),
ALLOCATABLE :: co(:, :, :), ct(:, :, :), h0(:, :), ht(:, :), pos(:, :, :), &
300 s0(:, :), si(:, :, :), sn(:, :, :), spin_c(:, :, :), spin_h(:, :), spin_s(:, :), &
301 spin_sin(:, :, :), st(:, :), t(:, :)
302 INTEGER :: col, expected, i, idx, info, j, kx, ky, &
303 n, orbital, phase, row, x, y
304 REAL(dp) :: cond, g, g0, mass, two_pi, wave(2)
306 two_pi = 8.0_dp*atan(1.0_dp)
313 ELSE IF (phase == 3)
THEN
317 CALL qwz_model(length, mass, h0, s0, pos, torus=.true.)
319 ALLOCATE (co(n, n, 2), si(n, n, 2))
324 co(i, i, j) = cos(two_pi*real(pos(i, i, j), dp)/length)
325 si(i, i, j) = sin(two_pi*real(pos(i, i, j), dp)/length)
329 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g0, cond, info)
330 IF (info /= 0 .OR. idx /= expected) error stop
'Periodic QWZ Chern phase failed'
332 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
333 IF (info /= 0 .OR. idx /= expected .OR. abs(g - g0) > 1.e-11_dp)
THEN
334 error stop
'Torus origin periodicity failed'
337 0.0_dp, 1.0_dp, .false., &
338 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
339 IF (info /= 0 .OR. idx /= expected .OR. abs(g - g0) > 1.e-11_dp)
THEN
340 error stop
'Periodic lattice translation covariance failed'
342 CALL localizer_periodic_evaluate(h0, s0, co(:, :, [2, 1]), si(:, :, [2, 1]), &
343 [0.0_dp, 0.0_dp], 0.0_dp, 1.0_dp, .false., &
344 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
345 IF (info /= 0 .OR. idx /= -expected .OR. abs(g - g0) > 1.e-11_dp)
THEN
346 error stop
'Periodic orientation reversal failed'
349 ALLOCATE (spin_h(2*n, 2*n), spin_s(2*n, 2*n), spin_c(2*n, 2*n, 2), spin_sin(2*n, 2*n, 2))
355 spin_h(n + 1:, n + 1:) = conjg(h0)
357 spin_h(i, n + i + 1) = 0.1_dp
358 spin_h(i + 1, n + i) = -0.1_dp
360 spin_h(n + 1:, :n) = conjg(transpose(spin_h(:n, n + 1:)))
362 spin_s(n + 1:, n + 1:) = s0
363 spin_c(:n, :n, :) = co
364 spin_c(n + 1:, n + 1:, :) = co
365 spin_sin(:n, :n, :) = si
366 spin_sin(n + 1:, n + 1:, :) = si
368 0.0_dp, 1.0_dp, .true., &
369 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
370 IF (info /= 0 .OR. idx /= abs(expected)) error stop
'Periodic spin-mixed Z2 phase failed'
371 spin_h(:, :) = spin_s
373 0.0_dp, 1.0_dp, .true., &
374 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
375 IF (info /= 0 .OR. idx /= 0) error stop
'Periodic atomic Pfaffian calibration failed'
376 DEALLOCATE (spin_h, spin_s, spin_c, spin_sin)
379 ALLOCATE (t(n, n), ht(n, n), st(n, n), ct(n, n, 2), sn(n, n, 2))
382 DO ky = 0, length - 1
383 DO kx = 0, length - 1
384 col = 2*(ky*length + kx) + 1
387 row = 2*(y*length + x) + 1
390 exp(cmplx(0.0_dp, two_pi*(x*kx + y*ky)/length, dp))/length
396 ht(:, :) = matmul(conjg(transpose(t)), matmul(h0, t))
398 DO ky = 0, length - 1
399 DO kx = 0, length - 1
400 col = 2*(ky*length + kx) + 1
401 wave = two_pi*[real(kx, dp), real(ky, dp)]/length
402 IF (abs(ht(col, col) - (mass + sum(cos(wave)))) > 1.e-12_dp)
THEN
403 error stop
'Periodic real-space/k-space Hamiltonian mismatch'
405 IF (abs(ht(col, col + 1) - cmplx(sin(wave(1)), -sin(wave(2)), dp)) > 1.e-12_dp)
THEN
406 error stop
'Periodic Bloch Hamiltonian offdiagonal mismatch'
411 ct(:, :, j) = matmul(conjg(transpose(t)), matmul(co(:, :, j), t))
412 sn(:, :, j) = matmul(conjg(transpose(t)), matmul(si(:, :, j), t))
415 0.0_dp, 1.0_dp, .false., &
416 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
417 IF (info /= 0 .OR. idx /= expected .OR. abs(g - g0) > 1.e-11_dp)
THEN
418 error stop
'Full k-mesh/real-space periodic localizer mismatch'
422 t(i, i) = (1.0_dp + mod(i, 5)/5.0_dp)*exp(cmplx(0.0_dp, 0.17_dp*i, dp))
423 IF (i < n) t(i, i + 1) = cmplx(0.07_dp, -0.04_dp, dp)
425 ht(:, :) = matmul(conjg(transpose(t)), matmul(h0, t))
426 st(:, :) = matmul(conjg(transpose(t)), t)
428 ct(:, :, j) = matmul(conjg(transpose(t)), matmul(co(:, :, j), t))
429 sn(:, :, j) = matmul(conjg(transpose(t)), matmul(si(:, :, j), t))
432 7.0_dp, 1.0_dp, .false., &
433 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
434 IF (info /= 0 .OR. idx /= expected .OR. abs(g - g0) > 1.e-11_dp)
THEN
435 error stop
'Periodic metric/energy covariance failed'
438 0.0_dp, 2.0_dp, .false., &
439 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
440 IF (info /= 0 .OR. idx /= expected .OR. abs(g - 2*g0) > 1.e-11_dp)
THEN
441 error stop
'Periodic energy-scale covariance failed'
443 DEALLOCATE (t, ht, st, ct, sn)
446 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
447 IF (info /= -1) error stop
'Zero torus energy scale accepted'
448 co(1, 2, 1) = co(1, 2, 1) + 0.1_dp
450 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
451 IF (info /= -1) error stop
'Non-Hermitian torus cosine accepted'
457 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, idx, g, cond, info)
458 IF (info /= 1) error stop
'Closed periodic localizer assigned an index'
459 DEALLOCATE (h0, s0, pos, co, si)
461 END SUBROUTINE periodic_tests
466 SUBROUTINE inertia_tests()
467 COMPLEX(KIND=dp) :: change(4, 4), matrix(4, 4), &
469 INTEGER :: exponent, i, j, m, p, RESULT
472 matrix(1, 2) = cmplx(0.0_dp, 2.0_dp,
dp)
473 matrix(2, 1) = conjg(matrix(1, 2))
474 matrix(3, 3) = 1.e-12_dp
475 matrix(4, 4) = 3.0_dp
478 change(i, i) = cmplx(1.0_dp + 0.2_dp*i, 0.1_dp*i,
dp)
480 change(i, j) = cmplx(0.03_dp*j, -0.07_dp*i,
dp)
483 transformed = matmul(conjg(transpose(change)), matmul(matrix, change))
484 DO exponent = -150, 150, 150
486 IF (result /= 0 .OR. p /= 3 .OR. m /= 1) error stop
'LDL block inertia or congruence failed'
488 matrix(3, 3) = -1.e-12_dp
490 IF (result /= 0 .OR. p /= 2 .OR. m /= 2) error stop
'LDL gap crossing failed'
491 matrix(3, 3) = 0.0_dp
493 IF (result /= 1) error stop
'Singular LDL accepted'
494 matrix(2, 1) = matrix(1, 2)
496 IF (result /= -1) error stop
'Complex symmetric matrix accepted as Hermitian'
498 matrix(1, 2) = cmplx(0.0_dp, 1.e-12_dp,
dp)
499 matrix(2, 1) = conjg(matrix(1, 2))
500 matrix(3, 3) = 1.0_dp
501 matrix(4, 4) = -1.0_dp
503 IF (result /= 0 .OR. p /= 2 .OR. m /= 2) error stop
'Small imaginary coupling discarded'
504 END SUBROUTINE inertia_tests
509 SUBROUTINE real_inertia_tests()
510 COMPLEX(dp),
ALLOCATABLE :: cmatrix(:, :), phases(:)
511 INTEGER :: exponent, i, info, j, m, n, negative, p
512 REAL(dp) :: pair(2, 2), scale
513 REAL(dp),
ALLOCATABLE :: change(:, :), diagonal(:, :), &
517 ALLOCATE (diagonal(n, n), change(n, n), matrix(n, n), phases(n), cmatrix(n, n))
520 change(i, i) = 0.5_dp + real(i, dp)/n
521 phases(i) = exp(cmplx(0.0_dp, 0.37_dp*i, dp))
523 change(i, j) = 0.1_dp*sin(real(i + 3*j, dp))
529 diagonal(i, i) = 1.0_dp + real(i, dp)/n
530 IF (i <= negative) diagonal(i, i) = -diagonal(i, i)
532 matrix(:, :) = matmul(transpose(change), matmul(diagonal, change))
535 cmatrix(i, j) = conjg(phases(i))*matrix(i, j)*phases(j)
538 DO exponent = -150, 150, 150
539 scale = 10.0_dp**exponent
541 IF (info /= 0 .OR. p /= n - negative .OR. m /= negative) error stop
'Real LDL signature failed'
543 IF (info /= 0 .OR. p /= n - negative .OR. m /= negative) error stop
'Complex LDL signature failed'
545 IF (info /= 0 .OR. p /= n - negative .OR. m /= negative) error stop
'Real LDL dispatch failed'
548 DEALLOCATE (diagonal, change, matrix, phases, cmatrix)
550 pair = reshape([0.0_dp, 2.0_dp, 2.0_dp, 0.0_dp], [2, 2])
552 IF (info /= 0 .OR. p /= 1 .OR. m /= 1) error stop
'Zero-diagonal real 2x2 pivot failed'
555 IF (info /= -1) error stop
'Nonsymmetric real matrix accepted'
558 IF (info /= 1) error stop
'Singular real matrix accepted'
559 END SUBROUTINE real_inertia_tests
564 SUBROUTINE gap_tests()
565 COMPLEX(dp) :: change(2, 2), h(2, 2), hc(2, 2), &
566 r(2, 2, 2), s(2, 2), sc(2, 2)
567 INTEGER :: i, index, status
568 REAL(dp) :: crossing(5), expected, gap, ratio, trace
570 h = reshape([1.0_dp, 20.0_dp, 20.0_dp, 399.0_dp], [2, 2])
575 trace = real(h(1, 1) + h(2, 2), dp)
576 expected = 1.0_dp/(trace + sqrt(trace**2 + 4.0_dp))
578 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, index, gap, ratio, status)
579 IF (status /= 0 .OR. index /= 0 .OR. abs(gap - expected) > 1.e-12_dp) error stop
'Analytic LDL/gap separation failed'
580 change = reshape([0.5_dp, 0.0_dp, 0.2_dp, 3.0_dp], [2, 2])
581 hc = matmul(transpose(change), matmul(h, change))
582 sc = matmul(transpose(change), matmul(s, change))
584 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, index, gap, ratio, status)
585 IF (status /= 0 .OR. abs(gap - expected) > 1.e-12_dp) error stop
'Metric LDL/gap separation failed'
586 crossing = [-1.e-6_dp, -1.e-12_dp, 0.0_dp, 1.e-12_dp, 1.e-6_dp]
589 DO i = 1,
SIZE(crossing)
590 h(1, 1) = crossing(i)
592 1.e-10_dp, 1.e-10_dp, 1.e-9_dp, index, gap, ratio, status)
593 IF (i == 1 .OR. i == 5)
THEN
594 IF (status /= 0 .OR. abs(gap - 5.e-7_dp) > 1.e-14_dp) error stop
'Resolved gap crossing failed'
596 IF (status /= 1) error stop
'Unresolved gap assigned an index'
599 END SUBROUTINE gap_tests
604 SUBROUTINE pfaffian_orientation_tests()
605 INTEGER :: exponent, i, j, n, pf_sign, sample, &
607 INTEGER,
ALLOCATABLE :: permutation(:)
608 REAL(dp) :: exact, scale
609 REAL(dp),
ALLOCATABLE :: a(:, :), change(:, :), transformed(:, :)
612 ALLOCATE (a(n, n), change(n, n), transformed(n, n), permutation(n))
617 a(i, j) = sin(real(11*i + 17*j + sample, dp))
621 a(i, i + 1) = a(i, i + 1) + 3.0_dp
623 a(:, :) = a - transpose(a)
624 exact = pfaffian_polynomial(a)
625 IF (abs(exact) < 1.e-6_dp) error stop
'Ill-conditioned Pfaffian fixture'
626 permutation(:) = [(i, i=1, n)]
627 permutation(:2) = [2, 1]
628 DO exponent = -150, 150, 150
629 scale = 10.0_dp**exponent
631 IF (status /= 0 .OR. pf_sign /= int(sign(1.0_dp, exact))) error stop
'Pfaffian polynomial sign failed'
633 IF (status /= 0 .OR. pf_sign /= (-1)**(n/2)*int(sign(1.0_dp, exact))) error stop
'Negative Pfaffian scale failed'
635 IF (status /= 0 .OR. pf_sign /= -int(sign(1.0_dp, exact))) error stop
'Equal determinant/opposite Pfaffian failed'
639 change(i, i) = 0.8_dp + 0.1_dp*i
640 IF (i < n) change(i, i + 1) = 0.1_dp
642 change(1, :) = -change(1, :)
643 transformed(:, :) = matmul(change, matmul(a, transpose(change)))
645 IF (status /= 0 .OR. pf_sign /= -int(sign(1.0_dp, exact))) error stop
'Pfaffian congruence orientation failed'
647 DEALLOCATE (a, change, transformed, permutation)
655 a(:, :) = a - transpose(a)
657 IF (status /= -2 .OR. pf_sign /= 0) error stop
'Pfaffian polynomial cancellation ignored'
658 END SUBROUTINE pfaffian_orientation_tests
665 RECURSIVE FUNCTION pfaffian_polynomial(a)
RESULT(value)
666 REAL(dp),
INTENT(IN) :: a(:, :)
669 INTEGER :: i, j, n, keep(SIZE(a, 1) - 2)
678 keep = pack([(i, i=2, n)], [(i /= j, i=2, n)])
679 value =
value + real((-1)**j, dp)*a(1, j)*pfaffian_polynomial(a(keep, keep))
681 END FUNCTION pfaffian_polynomial
696 SUBROUTINE evaluate(h, s, r, point, energy, kappa, aii, invariant, gap, status)
697 COMPLEX(KIND=dp),
INTENT(IN) :: h(:, :), s(:, :), r(:, :, :)
698 REAL(KIND=
dp),
INTENT(IN) :: point(2), energy, kappa
699 LOGICAL,
INTENT(IN) :: aii
700 INTEGER,
INTENT(OUT) :: invariant
701 REAL(KIND=
dp),
INTENT(OUT) :: gap
702 INTEGER,
INTENT(OUT) :: status
705 1.e-9_dp, invariant, gap, ratio, status)
706 END SUBROUTINE evaluate
717 SUBROUTINE qwz_model(length, mass, h, s, r, torus)
718 INTEGER,
INTENT(IN) :: length
719 REAL(KIND=
dp),
INTENT(IN) :: mass
720 COMPLEX(KIND=dp),
ALLOCATABLE,
INTENT(OUT) :: h(:, :), s(:, :), r(:, :, :)
721 LOGICAL,
INTENT(IN),
OPTIONAL :: torus
723 COMPLEX(KIND=dp) :: tx(2, 2), ty(2, 2)
724 INTEGER :: i, j, n, orbital, x, y
727 ALLOCATE (h(n, n), s(n, n), r(n, n, 2))
734 tx(1, 2) = cmplx(0.0_dp, -0.5_dp,
dp)
743 i = 2*((y - 1)*length + x) - 1
745 h(i + 1, i + 1) = -mass
753 h(i:i + 1, j:j + 1) = tx
754 h(j:j + 1, i:i + 1) = conjg(transpose(tx))
758 h(i:i + 1, j:j + 1) = ty
759 h(j:j + 1, i:i + 1) = conjg(transpose(ty))
761 IF (
PRESENT(torus))
THEN
762 IF (torus .AND. x == length)
THEN
763 j = 2*(y - 1)*length + 1
764 h(i:i + 1, j:j + 1) = tx
765 h(j:j + 1, i:i + 1) = conjg(transpose(tx))
767 IF (torus .AND. y == length)
THEN
769 h(i:i + 1, j:j + 1) = ty
770 h(j:j + 1, i:i + 1) = conjg(transpose(ty))
775 END SUBROUTINE qwz_model
784 USE ieee_arithmetic,
ONLY: ieee_value, ieee_quiet_nan
785#if defined(__HAS_IEEE_EXCEPTIONS)
786 USE ieee_exceptions,
ONLY: ieee_all, ieee_get_halting_mode, ieee_set_halting_mode
791 COMPLEX(dp),
PARAMETER :: ii = cmplx(0.0_dp, 1.0_dp,
dp)
792 INTEGER,
PARAMETER :: side = 3, sites = side**3, n = 4*sites
793 REAL(
dp),
PARAMETER :: masses(3) = [0.0_dp, 4.0_dp, 2.0_dp]
794 COMPLEX(dp) :: h(n, n), s(n, n), r(n, n, 3), u(n, n), hc(n, n), sc(n, n), rc(n, n, 3)
795 COMPLEX(dp) :: pauli(2, 2, 3), a(2*n, 2*n), dummy(1, 1), work(10*n)
796 REAL(
dp) :: singular(2*n), rwork(10*n), gap, reference, ratio, mass, shift(3), defect, lower, upper, midpoint
797 INTEGER :: i, j, axis, model, index, expected, status, sign_product, kx, ky, kz, io
798#if defined(__HAS_IEEE_EXCEPTIONS)
799 LOGICAL :: halt(size(ieee_all)), current_halt(size(ieee_all))
800 CALL ieee_get_halting_mode(ieee_all, halt)
806 pauli(1, 2, 1) = 1.0_dp
807 pauli(2, 1, 1) = 1.0_dp
810 pauli(1, 1, 3) = 1.0_dp
811 pauli(2, 2, 3) = -1.0_dp
814 CALL dirac_model(mass)
820 sign_product = sign_product*int(sign(1.0_dp, mass + kx + ky + kz))
824 expected = (1 - sign_product)/2
825 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
826 IF (status /= 0 .OR. index /= expected) error stop
'3D strong/trivial parity mismatch'
830 a(n + 1:, n + 1:) = h
834 a((i - 1)*n + 1:i*n, (j - 1)*n + 1:j*n) = &
835 a((i - 1)*n + 1:i*n, (j - 1)*n + 1:j*n) - 0.5_dp*ii*pauli(i, j, axis)*r(:, :, axis)
839#if defined(__HAS_IEEE_EXCEPTIONS)
840 CALL ieee_set_halting_mode(ieee_all, .false.)
842 CALL zgesvd(
'N',
'N', 2*n, 2*n, a, 2*n, singular, dummy, 1, dummy, 1, work,
SIZE(work), rwork, status)
843#if defined(__HAS_IEEE_EXCEPTIONS)
844 CALL ieee_set_halting_mode(ieee_all, halt)
846 IF (status /= 0 .OR. abs(reference - minval(singular)) > 2.e-12_dp) error stop
'3D singular gap mismatch'
847 IF (io > 0)
WRITE (io,
'(A,F4.1,I3,2ES18.9)')
'3D Dirac mass, index, gap, SVD error: ', &
848 mass, expected, reference, abs(reference - minval(singular))
854 u(i, i) = cmplx(0.8_dp + 0.004_dp*i, 0.07_dp*sin(real(i,
dp)),
dp)
855 u(i + n/2, i + n/2) = conjg(u(i, i))
856 u(i, i + n/2) = cmplx(0.08_dp, 0.03_dp,
dp)
857 u(i + n/2, i) = -conjg(u(i, i + n/2))
859 u(i, i + 1) = cmplx(0.02_dp, 0.01_dp,
dp)
860 u(i + n/2, i + n/2 + 1) = conjg(u(i, i + 1))
863 hc = matmul(conjg(transpose(u)), matmul(h, u))
864 sc = matmul(conjg(transpose(u)), matmul(s, u))
866 rc(:, :, axis) = matmul(conjg(transpose(u)), matmul(r(:, :, axis), u))
868 CALL evaluate(hc, sc, rc, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
869 defect = abs(gap - reference)
870 IF (status /= 0 .OR. index /= 1 .OR. defect > 3.e-12_dp) error stop
'3D nonorthogonal spin-mixing basis'
871 IF (io > 0)
WRITE (io,
'(A,ES18.9)')
'3D nonorthogonal spin-mixing gap residual: ', defect
872 shift = [1.2_dp, -0.8_dp, 0.4_dp]
874 rc(:, :, axis) = r(:, :, axis) + shift(axis)*s
876 CALL evaluate(h + 3.0_dp*s, s, rc, shift, 3.0_dp)
877 IF (status /= 0 .OR. index /= 1 .OR. abs(gap - reference) > 3.e-12_dp) error stop
'3D origin shifts'
878 rc(:, :, 1) = 0.6_dp*r(:, :, 1) + 0.8_dp*r(:, :, 2)
879 rc(:, :, 2) = -0.8_dp*r(:, :, 1) + 0.6_dp*r(:, :, 2)
880 rc(:, :, 3) = -r(:, :, 3)
881 CALL evaluate(h, s, rc, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
882 IF (status /= 0 .OR. index /= 1 .OR. abs(gap - reference) > 3.e-12_dp) error stop
'3D reflection/rotation'
885 1.e-10_dp, 1.e-10_dp, 1.e-10_dp, index, gap, ratio, status)
886 IF (status /= 0 .OR. index /= 0) error stop
'3D finite-size counterexample lost'
890 midpoint = 0.5_dp*(lower + upper)
892 1.e-10_dp, 1.e-10_dp, 0.0_dp, index, gap, ratio, status)
893 IF (status == 1)
EXIT
894 IF (status /= 0) error stop
'3D transition factorization failed'
902 1.e-10_dp, 1.e-10_dp, 1.e-8_dp, index, gap, ratio, status)
903 IF (status /= 1) error stop
'3D closing gap assigned an index'
904 IF (io > 0)
WRITE (io,
'(A,2ES18.9)')
'3D localizer transition scale and unresolved gap: ', midpoint, gap
906 1.e-10_dp, -1.0_dp, 1.e-10_dp, index, gap, ratio, status)
907 IF (status /= -1) error stop
'3D invalid metric tolerance accepted'
909 1.e-10_dp, 1.e-10_dp, ieee_value(0.0_dp, ieee_quiet_nan), index, gap, ratio, status)
910 IF (status /= -1) error stop
'3D nonfinite gap tolerance accepted'
911 h(1, 1) = h(1, 1) + 0.1_dp
912 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
913 IF (status /= -3) error stop
'3D broken time reversal accepted'
916 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
917 IF (status /= 1 .OR. index /= 0) error stop
'3D zero gap accepted'
919 s(n/2 + 1, n/2 + 1) = -1.0_dp
920 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
921 IF (status /= -2) error stop
'3D indefinite metric accepted'
922 h(1, 1) = ieee_value(0.0_dp, ieee_quiet_nan)
923 CALL evaluate(h, s, r, [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp)
924 IF (status /= -1) error stop
'3D nonfinite operator accepted'
925#if defined(__HAS_IEEE_EXCEPTIONS)
926 CALL ieee_get_halting_mode(ieee_all, current_halt)
927 IF (any(halt .NEQV. current_halt)) error stop
'3D localizer changed IEEE exception modes'
929 IF (io > 0)
WRITE (io, *)
'3D AII determinant, generalized gap, basis, origin, TR and finite-size tests passed.'
936 INTEGER,
PARAMETER :: m = 64, quarter = m/4
938 COMPLEX(dp) :: block(m, m), metric(m/2, m/2), &
939 unused(1, 1), workspace(5*m)
940 INTEGER :: col, col_sign, info, orientation, &
941 paired_col, paired_row, RESULT, row, &
943 REAL(dp) :: matrix(m, m), measured_gap, &
944 metric_condition, real_work(5*m), &
949 metric(row, row) = 1.0_dp
953 matrix(row, row) = 1.0_dp
954 matrix(row, :row - 1) = -1.0_dp
955 matrix(row, m) = 1.0_dp + 0.25_dp*
modulo(row, 3)
957 DO orientation = 0, 1
959 IF (orientation == 1) matrix(1, :) = -matrix(1, :)
962 paired_col = (3 - (col - 1)/quarter)*quarter +
modulo(col - 1, quarter) + 1
963 col_sign = merge(1, -1, col <= quarter .OR. col > 3*quarter)
965 paired_row = (3 - (row - 1)/quarter)*quarter +
modulo(row - 1, quarter) + 1
966 row_sign = merge(1, -1, row <= quarter .OR. row > 3*quarter)
967 block(row, col) = 0.5_dp*(matrix(row, col) + row_sign*col_sign*matrix(paired_row, paired_col) + &
968 ii*(col_sign*matrix(row, paired_col) - row_sign*matrix(paired_row, col)))
972 result, measured_gap, metric_condition, info)
973 IF (info /= 0 .OR. result /= orientation) error stop
'3D high-growth determinant sign'
974#if defined(__HAS_IEEE_EXCEPTIONS)
975 CALL ieee_set_halting_mode(ieee_all, .false.)
977 CALL zgesvd(
'N',
'N', m, m, block, m, values, unused, 1, unused, 1, workspace, &
978 SIZE(workspace), real_work, info)
979#if defined(__HAS_IEEE_EXCEPTIONS)
980 CALL ieee_set_halting_mode(ieee_all, halt)
982 svd_gap = minval(values)
983 IF (info /= 0 .OR. abs(measured_gap - svd_gap) > 1.e-12_dp) error stop
'3D high-growth singular gap'
984 IF (io > 0)
WRITE (io,
'(A,I2,2ES18.9)')
'3D high-growth determinant, gap, SVD error: ', &
985 result, measured_gap, abs(measured_gap - svd_gap)
991 block(row, row) = real(col, dp)
994 result, measured_gap, metric_condition, info)
995 IF (info /= 0 .OR. result /= 0 .OR. abs(measured_gap - 1.0_dp) > 1.e-12_dp)
THEN
996 error stop
'3D atomic reference orientation'
1009 SUBROUTINE evaluate(hh, ss, rr, point, energy)
1010 COMPLEX(dp),
INTENT(IN) :: hh(:, :), ss(:, :), rr(:, :, :)
1011 REAL(dp),
INTENT(IN) :: point(3), energy
1014 index, gap, ratio, status)
1015 END SUBROUTINE evaluate
1020 SUBROUTINE dirac_model(m)
1021 REAL(dp),
INTENT(IN) :: m
1023 INTEGER :: col, direction, neighbor, orbital, &
1024 other, pos(3), row, site, spin, x, y, z
1033 site = 1 + x + side*y + side**2*z
1036 row = site + sites*(
orbital - 1) + 2*sites*(spin - 1)
1037 s(row, row) = 1.0_dp
1038 h(row, row) = m*real(3 - 2*
orbital, dp)
1039 r(row, row, :) = real(pos - 1, dp)
1041 IF (pos(direction) == side - 1) cycle
1042 neighbor = site + side**(direction - 1)
1043 col = neighbor + sites*(
orbital - 1) + 2*sites*(spin - 1)
1044 h(row, col) = 0.5_dp*real(3 - 2*
orbital, dp)
1045 h(col, row) = conjg(h(row, col))
1047 col = neighbor + sites*(2 -
orbital) + 2*sites*(other - 1)
1048 h(row, col) = -0.5_dp*ii*pauli(spin, other, direction)
1049 h(col, row) = conjg(h(row, col))
1057 END SUBROUTINE dirac_model
1071 USE ieee_arithmetic,
ONLY: ieee_quiet_nan, &
1082#include "./base/base_uses.f90"
1085 INTEGER,
PARAMETER :: n = 12, nb = 6, bs = 2
1089 INTEGER,
POINTER :: process_grid(:, :), row_dist(:), col_dist(:), sizes(:)
1090 COMPLEX(dp) :: transform(n, n), u(n, n), rotation(n, n), scaled(n, n), hdense(n, n), sdense(n, n), exact(n, n)
1091 COMPLEX(dp),
ALLOCATABLE :: result(:, :)
1092 REAL(
dp) :: energies(n), residuals(4), difference, maximum_error, energy, scale, gap(2), metric_ratio, exact_gap
1093 INTEGER :: i, j, mode, nr, nc, io, status
1094 CHARACTER(LEN=32) :: argument
1097 CALL dbcsr_init_lib(para_env%get_handle(), io)
1098 CALL init_fft(
'FFTSG', alltoall=.false., pool_limit=4, wisdom_file=
'', plan_style=1)
1099 nr = para_env%num_pe
1101 DO i = 1, command_argument_count()
1102 CALL get_command_argument(i, argument)
1103 IF (trim(argument) ==
'--column-grid')
THEN
1105 nc = para_env%num_pe
1108 ALLOCATE (process_grid(0:nr - 1, 0:nc - 1), row_dist(nb), col_dist(nb), sizes(nb))
1109 process_grid = reshape([(i, i=0, para_env%num_pe - 1)], [nr, nc])
1110 row_dist = [(
modulo(i - 1, nr), i=1, nb)]
1111 col_dist = [(
modulo(i - 1, nc), i=1, nb)]
1114 row_dist=row_dist, col_dist=col_dist)
1117 maximum_error = 0.0_dp
1122 energies(i) = 0.01_dp*(i - n/2) - 0.005_dp
1123 transform(i, i) = 1.0_dp
1125 u(i, j) = exp(cmplx(0.0_dp,
twopi*real((i - 1)*(j - 1),
dp)/n,
dp))/sqrt(real(n,
dp))
1127 IF (mode == 0) cycle
1128 transform(i, i) = 0.5_dp + 0.1_dp*i
1129 IF (i < n) transform(i, i + 1) = cmplx(0.13_dp, -0.08_dp,
dp)
1131 IF (mode == 2) transform(n, n) = 0.1_dp
1132 IF (mode == 4) energies = energies + 0.5_dp
1133 IF (mode == 5) energies = energies - 0.5_dp
1137 transform(:n/2, n/2 + 1:) = 0.0_dp
1138 transform(n/2 + 1:, :n/2) = 0.0_dp
1139 transform(n/2 + 1:, n/2 + 1:) = conjg(transform(:n/2, :n/2))
1141 energies(i) = 0.01_dp*(i - n/4) - 0.005_dp
1142 energies(n/2 + i) = energies(i)
1143 rotation(i, i) = cos(0.37_dp)
1144 rotation(n/2 + i, n/2 + i) = cos(0.37_dp)
1145 rotation(i, n/2 + i) = sin(0.37_dp)
1146 rotation(n/2 + i, i) = -sin(0.37_dp)
1148 u(i, j) = exp(cmplx(0.0_dp,
twopi*real((i - 1)*(j - 1),
dp)/(n/2),
dp))/sqrt(real(n/2,
dp))
1151 u(n/2 + 1:, n/2 + 1:) = conjg(u(:n/2, :n/2))
1152 u = matmul(rotation, u)
1154 scaled = u*spread(energies, 1, n)
1155 hdense = matmul(conjg(transpose(transform)), matmul(matmul(scaled, conjg(transpose(u))), transform))
1156 sdense = matmul(conjg(transpose(transform)), transform)
1157 scaled = u*spread(sign(scale, energies - energy), 1, n)
1158 exact = matmul(conjg(transpose(transform)), matmul(matmul(scaled, conjg(transpose(u))), transform))
1159 CALL make_operator(hdense, h)
1160 CALL make_operator(sdense, s)
1162 IF (status /= 0)
THEN
1163 IF (io > 0)
WRITE (io, *)
'Flatten failure: ', mode, status, residuals
1164 cpabort(
'Distributed spectral flattening failed')
1167 difference = maxval(abs(result - exact))
1168 maximum_error = max(maximum_error, difference)
1169 IF (difference > 1.e-9_dp)
THEN
1170 cpabort(
'Covariant sign differs from exact eigensystem')
1173 IF (maxval(abs(result(:n/2, :n/2) - conjg(result(n/2 + 1:, n/2 + 1:)))) > 1.e-9_dp)
THEN
1174 cpabort(
'Flattening broke physical TR diagonal blocks')
1176 IF (maxval(abs(result(:n/2, n/2 + 1:) + conjg(result(n/2 + 1:, :n/2)))) > 1.e-9_dp)
THEN
1177 cpabort(
'Flattening broke physical TR spin mixing')
1182 IF (maxval(abs(result - hdense)) > 1.e-14_dp)
THEN
1183 cpabort(
'Flattening modified input Hamiltonian')
1187 IF (maxval(abs(result - sdense)) > 1.e-14_dp)
THEN
1188 cpabort(
'Flattening modified input metric')
1193 para_env, flat, gap, metric_ratio, residuals, status)
1194 IF (status /= 0) cpabort(
'Checked flattening failed')
1195 exact_gap = minval(abs(energies - energy))
1196 IF (gap(1) > exact_gap + 1.e-10_dp .OR. gap(2) < exact_gap - 1.e-10_dp)
THEN
1197 cpabort(
'Input electronic gap differs from reference')
1199 IF (metric_ratio <= 1.e-10_dp) cpabort(
'Invalid positive metric bound')
1201 difference = maxval(abs(result - exact))
1202 maximum_error = max(maximum_error, difference)
1203 IF (difference > 1.e-9_dp)
THEN
1204 cpabort(
'Checked flattening changed the exact result')
1215 sdense(i, i) = 1.0_dp
1216 hdense(i, i) = 1.0_dp
1218 hdense(1, 1) = 0.0_dp
1219 CALL make_operator(hdense, h)
1220 CALL make_operator(sdense, s)
1222 IF (status /= 1) cpabort(
'Singular spectral sign was accepted')
1224 para_env, flat, gap, metric_ratio, residuals, status)
1225 IF (status /= 1) cpabort(
'Checked flattening accepted a zero spectral mode')
1227 IF (status /= -1) cpabort(
'Negative flattening scale was accepted')
1229 para_env, flat, residuals, status)
1230 IF (status /= -1) cpabort(
'Nonfinite energy was accepted')
1233 CALL make_operator(hdense, h)
1235 IF (status /= 1) cpabort(
'Zero Hamiltonian sign was accepted')
1237 hdense(1, 2) = 1.0_dp
1238 CALL make_operator(hdense, h)
1240 IF (status /= -1) cpabort(
'Non-Hermitian Hamiltonian was accepted')
1244 hdense(1, 1) = 1.e-11_dp
1245 CALL make_operator(hdense, h)
1246 CALL make_operator(sdense, s)
1248 para_env, flat, gap, metric_ratio, residuals, status)
1249 IF (status /= 1) cpabort(
'Unresolved near-zero spectral mode was accepted')
1251 sdense(1, 1) = -1.0_dp
1252 CALL make_operator(sdense, s)
1254 para_env, flat, gap, metric_ratio, residuals, status)
1255 IF (status /= -2) cpabort(
'Indefinite metric was accepted')
1257 sdense(1, 1) = 1.e-12_dp
1258 CALL make_operator(sdense, s)
1260 para_env, flat, gap, metric_ratio, residuals, status)
1261 IF (status /= -2) cpabort(
'Ill-conditioned metric was accepted')
1265 IF (io > 0)
WRITE (io,
'(A,ES14.5)')
'Spectral flattening exact-matrix maximum error: ', maximum_error
1267 DEALLOCATE (process_grid, row_dist, col_dist, sizes)
1268 CALL dbcsr_finalize_lib()
1277 INTEGER :: band, grid(3), k, kr(3), m, ncell, &
1278 nscalar, nsmall, nspin, p, pnext, &
1279 r(3), rnext, row, t, tnext
1280 REAL(dp) :: bloch_error, bloch_gap, norm_error, &
1283 bloch_error = 0.0_dp
1288 IF (m == 2) grid = [1, 3, 1]
1289 IF (m == 3) grid = [1, 1, 3]
1296 sizes = [1, 3, 1, 3, 1, 3]
1298 IF (m == 6) grid = 1
1299 ncell = product(grid)
1300 nscalar = n/(nspin*ncell)
1301 nsmall = nscalar*nspin
1305 t =
modulo((row - 1)/nscalar, ncell)
1306 p = ((row - 1)/(ncell*nscalar))*nscalar +
modulo(row - 1, nscalar)
1307 r = [
modulo(t, grid(1)),
modulo(t/grid(1), grid(2)), t/(grid(1)*grid(2))]
1308 transform(row, row) = 1.0_dp + 0.03_dp*p
1309 pnext =
modulo(p + 1, nsmall)
1310 rnext = (pnext/nscalar)*ncell*nscalar + t*nscalar +
modulo(pnext, nscalar) + 1
1311 transform(row, rnext) = transform(row, rnext) + cmplx(0.07_dp, -0.04_dp, dp)
1312 tnext =
modulo(t + 1, ncell)
1313 rnext = (p/nscalar)*ncell*nscalar + tnext*nscalar +
modulo(p, nscalar) + 1
1315 IF (m /= 4) transform(row, rnext) = transform(row, rnext) + cmplx(0.05_dp, 0.02_dp, dp)
1317 kr = [
modulo(k, grid(1)),
modulo(k/grid(1), grid(2)), k/(grid(1)*grid(2))]
1318 DO band = 0, nsmall - 1
1319 phase =
twopi*(sum(real(kr*r, dp)/real(grid, dp)) + real(p*band, dp)/real(nsmall, dp))
1320 u(row, k*nsmall + band + 1) = exp(cmplx(0.0_dp, phase, dp))/sqrt(real(n, dp))
1321 energies(k*nsmall + band + 1) = 0.2_dp + 0.03_dp*band + 0.01_dp*cos(real(k, dp))
1322 IF (m == 7) energies(k*nsmall + band + 1) = 0.25_dp + 0.01_dp*cos(real(k, dp))
1323 IF (band < nsmall/2) energies(k*nsmall + band + 1) = -energies(k*nsmall + band + 1)
1327 scaled = u*spread(energies, 1, n)
1328 hdense = matmul(conjg(transpose(transform)), matmul(matmul(scaled, conjg(transpose(u))), transform))
1329 sdense = matmul(conjg(transpose(transform)), transform)
1330 scaled = u*spread(sign(scale, energies - energy), 1, n)
1331 exact = matmul(conjg(transpose(transform)), matmul(matmul(scaled, conjg(transpose(u))), transform))
1332 CALL make_operator(hdense, h)
1333 CALL make_operator(sdense, s)
1335 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1336 IF (status /= 0) cpabort(
'Bloch flattening failed')
1338 norm_error = maxval(abs(result - exact))
1339 bloch_error = max(bloch_error, norm_error)
1340 maximum_error = max(maximum_error, norm_error)
1341 ref_gap = minval(abs(energies - energy))
1342 IF (norm_error > 1.e-11_dp .OR. abs(bloch_gap - ref_gap) > 1.e-12_dp)
THEN
1343 cpabort(
'Bloch flattening differs from exact full-torus reference')
1347 para_env, flat, gap, metric_ratio, residuals, status)
1348 IF (status /= 0) cpabort(
'Full-torus reference flattening failed')
1350 IF (maxval(abs(result - exact)) > 1.e-10_dp)
THEN
1351 cpabort(
'Full-torus/Bloch sign mismatch')
1356 hdense(1, 1) = hdense(1, 1) + 0.01_dp
1357 CALL make_operator(hdense, h)
1359 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1360 IF (status /= -7) cpabort(
'Broken translations accepted')
1363 CALL make_operator(energy*sdense, h)
1365 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1366 IF (status /= 1) cpabort(
'Closed Bloch gap accepted')
1368 CALL make_operator(-sdense, s)
1370 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1371 IF (status /= -2) cpabort(
'Bloch flattening accepted an indefinite metric')
1380 hdense(row, row) = 1.0_dp
1381 sdense(row, row) = 0.5_dp*(1.0_dp + 1.e-12_dp)
1382 rnext = 1 +
modulo(row - 1 + n/2, n)
1383 sdense(row, rnext) = 0.5_dp*(1.0_dp - 1.e-12_dp)
1385 CALL make_operator(hdense, h)
1386 CALL make_operator(sdense, s)
1387 CALL localizer_flatten_bloch(h, s, [2, 1, 1], 1, 0.0_dp, scale, 1.e-9_dp, 1.e-10_dp, 1.e-8_dp, &
1388 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1389 IF (status /= -2) cpabort(
'Global Bloch metric bound failed')
1390 CALL localizer_flatten_bloch(h, s, [0, 1, 1], 1, 0.0_dp, scale, 1.e-9_dp, 1.e-10_dp, 1.e-8_dp, &
1391 para_env, flat, bloch_gap, metric_ratio, residuals, status)
1392 IF (status /= -1) cpabort(
'Invalid Bloch grid accepted')
1395 IF (io > 0)
WRITE (io,
'(A,ES14.5)')
'Seven Bloch flattening pencils; maximum error: ', bloch_error
1403 SUBROUTINE make_operator(dense, matrix)
1404 COMPLEX(dp),
INTENT(IN) :: dense(:, :)
1407 INTEGER :: col, first, last, left, right, row
1409 CALL dbcsr_create(matrix%real_part,
'FLATTEN REAL', distribution, dbcsr_type_no_symmetry, sizes, sizes)
1410 CALL dbcsr_create(matrix%imaginary_part, template=matrix%real_part)
1412 first = sum(sizes(:row - 1)) + 1
1413 last = sum(sizes(:row))
1415 IF (process_grid(row_dist(row), col_dist(col)) /= para_env%mepos) cycle
1416 left = sum(sizes(:col - 1)) + 1
1417 right = sum(sizes(:col))
1418 CALL dbcsr_put_block(matrix%real_part, row, col, real(dense(first:last, left:right),
dp))
1419 CALL dbcsr_put_block(matrix%imaginary_part, row, col, aimag(dense(first:last, left:right)))
1424 END SUBROUTINE make_operator