13 USE ieee_arithmetic,
ONLY: ieee_is_finite
19 REAL(KIND=
dp),
PARAMETER :: two_pi = 6.283185307179586476925286766559_dp
21 REAL(KIND=
dp),
PARAMETER :: crossing_tol = 1.e-12_dp
23 REAL(KIND=
dp),
PARAMETER :: gap_fraction = 0.3_dp
37 REAL(kind=
dp),
INTENT(IN) :: wcc(:, :)
38 INTEGER,
INTENT(OUT) :: invariant
39 REAL(kind=
dp),
INTENT(OUT) :: winding
40 INTEGER,
INTENT(OUT) :: status
41 REAL(kind=
dp),
INTENT(IN) :: closure_tol
43 REAL(kind=
dp),
PARAMETER :: max_phase_step = 0.25_dp
46 REAL(kind=
dp) :: delta
52 IF (
SIZE(wcc, 1) < 1 .OR. nline < 3 .OR. closure_tol <= 0.0_dp)
RETURN
53 IF (.NOT. all(ieee_is_finite(wcc)))
RETURN
55 IF (
wcc_distance(wcc(:, 1), wcc(:, nline)) > closure_tol)
RETURN
59 IF (
SIZE(wcc, 1)*
wcc_distance(wcc(:, i), wcc(:, i - 1)) >= max_phase_step)
RETURN
60 delta =
modulo(sum(wcc(:, i)) - sum(wcc(:, i - 1)) + 0.5_dp, 1.0_dp) - 0.5_dp
61 IF (abs(delta) >= max_phase_step)
RETURN
62 winding = winding + delta
65 IF (abs(winding - nint(winding)) > closure_tol)
RETURN
66 invariant = nint(winding)
76 REAL(kind=
dp),
INTENT(IN) :: wcc(:, :)
80 REAL(kind=
dp) :: delta, left_gap, left_size, right_gap, &
82 REAL(kind=
dp),
ALLOCATABLE :: sorted(:, :)
86 IF (n < 1 .OR.
SIZE(wcc, 2) < 2)
RETURN
87 ALLOCATE (sorted(n,
SIZE(wcc, 2)))
88 sorted(:, :) =
modulo(wcc, 1.0_dp)
89 DO i = 1,
SIZE(wcc, 2)
90 CALL sort_wcc(sorted(:, i))
92 DO i = 2,
SIZE(wcc, 2)
93 CALL largest_gap(sorted(:, i - 1), left_gap, left_size)
94 CALL largest_gap(sorted(:, i), right_gap, right_size)
95 IF (
wcc_distance(sorted(:, i - 1), sorted(:, i)) >= gap_fraction*min(left_size, right_size))
RETURN
97 delta = abs(sorted(j, i) - left_gap)
98 IF (min(delta, 1.0_dp - delta) <= gap_fraction*left_size)
RETURN
99 delta = abs(sorted(j, i - 1) - right_gap)
100 IF (min(delta, 1.0_dp - delta) <= gap_fraction*right_size)
RETURN
114 SUBROUTINE wilson_step(product, overlap, minimum_sv, status, sv_tol)
115 COMPLEX(KIND=dp),
INTENT(INOUT) :: product(:, :)
116 COMPLEX(KIND=dp),
INTENT(IN) :: overlap(:, :)
117 REAL(kind=
dp),
INTENT(OUT) :: minimum_sv
118 INTEGER,
INTENT(OUT) :: status
119 REAL(kind=
dp),
INTENT(IN) :: sv_tol
121 COMPLEX(KIND=dp),
ALLOCATABLE :: a(:, :), u(:, :), vh(:, :), work(:)
123 REAL(kind=
dp),
ALLOCATABLE :: rwork(:), sv(:)
128 IF (n < 1 .OR.
SIZE(overlap, 2) /= n .OR. any(shape(product) /= [n, n]))
RETURN
129 IF (.NOT. all(ieee_is_finite(real(overlap,
dp))))
RETURN
130 IF (.NOT. all(ieee_is_finite(aimag(overlap))))
RETURN
131 ALLOCATE (a(n, n), u(n, n), vh(n, n), sv(n), rwork(5*n), work(max(1, 4*n)))
133 CALL zgesvd(
'A',
'A', n, n, a, n, sv, u, n, vh, n, work,
SIZE(work), rwork, status)
134 IF (status /= 0)
RETURN
135 minimum_sv = minval(sv)
136 IF (minimum_sv <= sv_tol)
THEN
140 product = matmul(product, matmul(u, vh))
151 COMPLEX(KIND=dp),
INTENT(IN) :: product(:, :)
152 REAL(kind=
dp),
INTENT(OUT) :: wcc(:), berry
153 INTEGER,
INTENT(OUT) :: status
155 COMPLEX(KIND=dp) :: dummy(1, 1)
156 COMPLEX(KIND=dp),
ALLOCATABLE :: a(:, :), eig(:), work(:)
158 REAL(kind=
dp),
ALLOCATABLE :: rwork(:)
163 IF (n < 1 .OR.
SIZE(product, 2) /= n .OR.
SIZE(wcc) /= n)
RETURN
164 ALLOCATE (a(n, n), eig(n), work(max(1, 4*n)), rwork(2*n))
166 CALL zgeev(
'N',
'N', n, a, n, eig, dummy, 1, dummy, 1, work,
SIZE(work), rwork, status)
167 IF (status /= 0)
RETURN
168 wcc =
modulo(atan2(aimag(eig), real(eig,
dp))/two_pi, 1.0_dp)
170 berry = two_pi*(
modulo(sum(wcc) + 0.5_dp, 1.0_dp) - 0.5_dp)
183 REAL(kind=
dp),
INTENT(IN) :: wcc(:, :)
184 INTEGER,
INTENT(OUT) :: invariant, status
185 REAL(kind=
dp),
INTENT(IN) :: pair_tol
187 INTEGER :: crossings, i, j, lines, n
188 REAL(kind=
dp) :: gap_size, hi, lo
189 REAL(kind=
dp),
ALLOCATABLE :: gaps(:), sorted(:, :)
195 IF (n < 2 .OR. mod(n, 2) /= 0 .OR. lines < 2)
RETURN
196 IF (.NOT. all(ieee_is_finite(wcc)))
RETURN
197 ALLOCATE (sorted(n, lines), gaps(lines))
198 sorted(:, :) =
modulo(wcc, 1.0_dp)
200 CALL sort_wcc(sorted(:, i))
201 CALL largest_gap(sorted(:, i), gaps(i), gap_size)
204 IF (.NOT. kramers_pairs(sorted(:, 1), pair_tol))
RETURN
205 IF (.NOT. kramers_pairs(sorted(:, lines), pair_tol))
RETURN
208 lo = min(gaps(i - 1), gaps(i))
209 hi = max(gaps(i - 1), gaps(i))
211 IF (abs(sorted(j, i) - gaps(i - 1)) < crossing_tol)
THEN
215 IF (sorted(j, i) > lo .AND. sorted(j, i) < hi) crossings = crossings + 1
218 invariant = mod(crossings, 2)
229 REAL(kind=
dp),
INTENT(IN) :: a(:), b(:)
230 REAL(kind=
dp) :: distance
232 INTEGER :: i, j, n, shift
233 REAL(kind=
dp) :: delta, error
234 REAL(kind=
dp),
ALLOCATABLE :: aa(:), bb(:)
236 distance = huge(1.0_dp)
238 IF (n /=
SIZE(b) .OR. n < 1)
RETURN
239 ALLOCATE (aa(n), bb(n))
247 j = mod(i - 1 + shift, n) + 1
248 delta = abs(aa(i) - bb(j))
249 error = max(error, min(delta, 1.0_dp - delta))
251 distance = min(distance, error)
261 FUNCTION kramers_pairs(wcc, tolerance)
RESULT(paired)
262 REAL(kind=
dp),
INTENT(IN) :: wcc(:), tolerance
265 INTEGER :: i, j, k, n, offset
267 REAL(kind=
dp) :: delta
274 j = mod(i - 1 + offset, n) + 1
275 k = mod(i + offset, n) + 1
276 delta = abs(wcc(j) - wcc(k))
277 candidate = candidate .AND. min(delta, 1.0_dp - delta) <= tolerance
279 paired = paired .OR. candidate
281 END FUNCTION kramers_pairs
289 SUBROUTINE largest_gap(wcc, centre, width)
290 REAL(kind=
dp),
INTENT(IN) :: wcc(:)
291 REAL(kind=
dp),
INTENT(OUT) :: centre, width
294 REAL(kind=
dp) :: delta
300 delta = wcc(i + 1) - wcc(i)
302 delta = wcc(1) + 1.0_dp - wcc(n)
304 IF (delta > width)
THEN
306 centre =
modulo(wcc(i) + delta/2.0_dp, 1.0_dp)
309 END SUBROUTINE largest_gap
315 SUBROUTINE sort_wcc(values)
316 REAL(kind=
dp),
INTENT(INOUT) :: values(:)
319 REAL(kind=
dp) ::
value
321 DO i = 2,
SIZE(values)
325 IF (values(j) <=
value)
EXIT
326 values(j + 1) = values(j)
329 values(j + 1) =
value
331 END SUBROUTINE sort_wcc
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
Defines the basic variable types.
integer, parameter, public dp
Local Wilson-loop linear algebra, independent of the electronic-structure representation....
real(kind=dp) function, public wcc_distance(a, b)
Minimum maximal cyclic matching distance between two WCC sets.
subroutine, public wilson_step(product, overlap, minimum_sv, status, sv_tol)
Multiply by the unitary polar factor of an overlap. Reject rank-deficient links.
subroutine, public z2_from_wcc(wcc, invariant, status, pair_tol)
Largest-gap crossing parity for an ordered time-reversal half-surface. Endpoint degeneracy is necessa...
logical function, public surface_resolved(wcc)
Conservative neighbouring-line movement and largest-gap separation checks.
subroutine, public wilson_spectrum(product, wcc, berry, status)
Sorted Wilson eigenphases in reduced units and total Berry phase in radians.
subroutine, public chern_from_wcc(wcc, invariant, winding, status, closure_tol)
First Chern number from determinant Wilson-phase winding on a closed surface. Both transverse endpoin...