(git:26ffdda)
Loading...
Searching...
No Matches
topology_wilson.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!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Local Wilson-loop linear algebra, independent of the electronic-structure representation.
10!> WCC are arg(eigenvalue)/(2*pi), as in Z2Pack. The occupied subspace must be isolated.
11! **************************************************************************************************
13 USE ieee_arithmetic, ONLY: ieee_is_finite
14 USE kinds, ONLY: dp
15
16 IMPLICIT NONE
17 PRIVATE
19 REAL(KIND=dp), PARAMETER :: two_pi = 6.283185307179586476925286766559_dp
20 ! Reduced-coordinate tolerance for an ambiguous largest-gap crossing.
21 REAL(KIND=dp), PARAMETER :: crossing_tol = 1.e-12_dp
22 ! Fraction of the adjacent largest gap allowed for motion and gap separation.
23 REAL(KIND=dp), PARAMETER :: gap_fraction = 0.3_dp
24CONTAINS
25
26! **************************************************************************************************
27!> \brief First Chern number from determinant Wilson-phase winding on a closed surface.
28!> Both transverse endpoints must be present. This is not a Z2 half-surface.
29!> The sign follows Z2Pack: increasing transverse coordinate, fixed loop orientation.
30!> \param wcc Wilson centres, band index first and transverse line second
31!> \param invariant candidate integer, meaningful only for status zero
32!> \param winding unrounded winding
33!> \param status 0 success, -1 invalid data, -2 unclosed surface, -3 unresolved phase step
34!> \param closure_tol maximal endpoint WCC mismatch
35! **************************************************************************************************
36 SUBROUTINE chern_from_wcc(wcc, invariant, winding, status, closure_tol)
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
42
43 REAL(kind=dp), PARAMETER :: max_phase_step = 0.25_dp
44
45 INTEGER :: i, nline
46 REAL(kind=dp) :: delta
47
48 invariant = 0
49 winding = 0.0_dp
50 status = -1
51 nline = SIZE(wcc, 2)
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
54 status = -2
55 IF (wcc_distance(wcc(:, 1), wcc(:, nline)) > closure_tol) RETURN
56 status = -3
57 DO i = 2, nline
58 ! Avoid accepting a small aliased determinant step when many centres move.
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
63 END DO
64 status = -2
65 IF (abs(winding - nint(winding)) > closure_tol) RETURN
66 invariant = nint(winding)
67 status = 0
68 END SUBROUTINE chern_from_wcc
69
70! **************************************************************************************************
71!> \brief Conservative neighbouring-line movement and largest-gap separation checks.
72!> \param wcc centres, band index first and surface-line index second
73!> \return whether the sampled surface is locally resolved (not a proof between samples)
74! **************************************************************************************************
75 FUNCTION surface_resolved(wcc) RESULT(resolved)
76 REAL(kind=dp), INTENT(IN) :: wcc(:, :)
77 LOGICAL :: resolved
78
79 INTEGER :: i, j, n
80 REAL(kind=dp) :: delta, left_gap, left_size, right_gap, &
81 right_size
82 REAL(kind=dp), ALLOCATABLE :: sorted(:, :)
83
84 resolved = .false.
85 n = SIZE(wcc, 1)
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))
91 END DO
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
96 DO j = 1, n
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
101 END DO
102 END DO
103 resolved = .true.
104 END FUNCTION surface_resolved
105
106! **************************************************************************************************
107!> \brief Multiply by the unitary polar factor of an overlap. Reject rank-deficient links.
108!> \param product running Wilson matrix
109!> \param overlap overlap between adjacent occupied subspaces
110!> \param minimum_sv smallest singular value of this link
111!> \param status zero on success; negative for invalid/singular input; positive LAPACK failure
112!> \param sv_tol rank tolerance
113! **************************************************************************************************
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
120
121 COMPLEX(KIND=dp), ALLOCATABLE :: a(:, :), u(:, :), vh(:, :), work(:)
122 INTEGER :: n
123 REAL(kind=dp), ALLOCATABLE :: rwork(:), sv(:)
124
125 n = SIZE(overlap, 1)
126 status = -1
127 minimum_sv = 0.0_dp
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)))
132 a(:, :) = overlap
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
137 status = -2
138 RETURN
139 END IF
140 product = matmul(product, matmul(u, vh))
141 END SUBROUTINE wilson_step
142
143! **************************************************************************************************
144!> \brief Sorted Wilson eigenphases in reduced units and total Berry phase in radians.
145!> \param product Wilson matrix
146!> \param wcc sorted centres in [0,1)
147!> \param berry Berry phase in [-pi,pi)
148!> \param status zero on success
149! **************************************************************************************************
150 SUBROUTINE wilson_spectrum(product, wcc, berry, status)
151 COMPLEX(KIND=dp), INTENT(IN) :: product(:, :)
152 REAL(kind=dp), INTENT(OUT) :: wcc(:), berry
153 INTEGER, INTENT(OUT) :: status
154
155 COMPLEX(KIND=dp) :: dummy(1, 1)
156 COMPLEX(KIND=dp), ALLOCATABLE :: a(:, :), eig(:), work(:)
157 INTEGER :: n
158 REAL(kind=dp), ALLOCATABLE :: rwork(:)
159
160 n = SIZE(product, 1)
161 status = -1
162 berry = 0.0_dp
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))
165 a(:, :) = product
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)
169 CALL sort_wcc(wcc)
170 berry = two_pi*(modulo(sum(wcc) + 0.5_dp, 1.0_dp) - 0.5_dp)
171 END SUBROUTINE wilson_spectrum
172
173! **************************************************************************************************
174!> \brief Largest-gap crossing parity for an ordered time-reversal half-surface.
175!> Endpoint degeneracy is necessary but does not establish time-reversal symmetry.
176!> Sampling convergence and an isolated fixed-rank subspace must be checked by the caller.
177!> \param wcc Wilson centres, band index first and surface-line index second
178!> \param invariant Z2 parity, or -1 if checks fail
179!> \param status 0 success, -1 invalid input, -2 missing Kramers pairs, -3 ambiguous crossing
180!> \param pair_tol tolerance on boundary Kramers degeneracy, in reduced units
181! **************************************************************************************************
182 SUBROUTINE z2_from_wcc(wcc, invariant, status, pair_tol)
183 REAL(kind=dp), INTENT(IN) :: wcc(:, :)
184 INTEGER, INTENT(OUT) :: invariant, status
185 REAL(kind=dp), INTENT(IN) :: pair_tol
186
187 INTEGER :: crossings, i, j, lines, n
188 REAL(kind=dp) :: gap_size, hi, lo
189 REAL(kind=dp), ALLOCATABLE :: gaps(:), sorted(:, :)
190
191 invariant = -1
192 status = -1
193 n = SIZE(wcc, 1)
194 lines = SIZE(wcc, 2)
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)
199 DO i = 1, lines
200 CALL sort_wcc(sorted(:, i))
201 CALL largest_gap(sorted(:, i), gaps(i), gap_size)
202 END DO
203 status = -2
204 IF (.NOT. kramers_pairs(sorted(:, 1), pair_tol)) RETURN
205 IF (.NOT. kramers_pairs(sorted(:, lines), pair_tol)) RETURN
206 crossings = 0
207 DO i = 2, lines
208 lo = min(gaps(i - 1), gaps(i))
209 hi = max(gaps(i - 1), gaps(i))
210 DO j = 1, n
211 IF (abs(sorted(j, i) - gaps(i - 1)) < crossing_tol) THEN
212 status = -3
213 RETURN
214 END IF
215 IF (sorted(j, i) > lo .AND. sorted(j, i) < hi) crossings = crossings + 1
216 END DO
217 END DO
218 invariant = mod(crossings, 2)
219 status = 0
220 END SUBROUTINE z2_from_wcc
221
222! **************************************************************************************************
223!> \brief Minimum maximal cyclic matching distance between two WCC sets.
224!> \param a first WCC set
225!> \param b second WCC set
226!> \return distance, or huge if sizes differ
227! **************************************************************************************************
228 FUNCTION wcc_distance(a, b) RESULT(distance)
229 REAL(kind=dp), INTENT(IN) :: a(:), b(:)
230 REAL(kind=dp) :: distance
231
232 INTEGER :: i, j, n, shift
233 REAL(kind=dp) :: delta, error
234 REAL(kind=dp), ALLOCATABLE :: aa(:), bb(:)
235
236 distance = huge(1.0_dp)
237 n = SIZE(a)
238 IF (n /= SIZE(b) .OR. n < 1) RETURN
239 ALLOCATE (aa(n), bb(n))
240 aa(:) = modulo(a, 1.0_dp)
241 bb(:) = modulo(b, 1.0_dp)
242 CALL sort_wcc(aa)
243 CALL sort_wcc(bb)
244 DO shift = 0, n - 1
245 error = 0.0_dp
246 DO i = 1, 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))
250 END DO
251 distance = min(distance, error)
252 END DO
253 END FUNCTION wcc_distance
254
255! **************************************************************************************************
256!> \brief Test circularly adjacent Kramers pairs (including pairs across the branch cut).
257!> \param wcc sorted centres
258!> \param tolerance degeneracy tolerance
259!> \return whether one of the two cyclic pairings succeeds
260! **************************************************************************************************
261 FUNCTION kramers_pairs(wcc, tolerance) RESULT(paired)
262 REAL(kind=dp), INTENT(IN) :: wcc(:), tolerance
263 LOGICAL :: paired
264
265 INTEGER :: i, j, k, n, offset
266 LOGICAL :: candidate
267 REAL(kind=dp) :: delta
268
269 paired = .false.
270 n = SIZE(wcc)
271 DO offset = 0, 1
272 candidate = .true.
273 DO i = 1, n, 2
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
278 END DO
279 paired = paired .OR. candidate
280 END DO
281 END FUNCTION kramers_pairs
282
283! **************************************************************************************************
284!> \brief Find the midpoint of the largest gap between sorted centres.
285!> \param wcc sorted centres
286!> \param centre gap midpoint
287!> \param width gap width
288! **************************************************************************************************
289 SUBROUTINE largest_gap(wcc, centre, width)
290 REAL(kind=dp), INTENT(IN) :: wcc(:)
291 REAL(kind=dp), INTENT(OUT) :: centre, width
292
293 INTEGER :: i, n
294 REAL(kind=dp) :: delta
295
296 n = SIZE(wcc)
297 width = -1.0_dp
298 DO i = 1, n
299 IF (i < n) THEN
300 delta = wcc(i + 1) - wcc(i)
301 ELSE
302 delta = wcc(1) + 1.0_dp - wcc(n)
303 END IF
304 IF (delta > width) THEN
305 width = delta
306 centre = modulo(wcc(i) + delta/2.0_dp, 1.0_dp)
307 END IF
308 END DO
309 END SUBROUTINE largest_gap
310
311! **************************************************************************************************
312!> \brief In-place insertion sort of Wilson centres.
313!> \param values values to sort
314! **************************************************************************************************
315 SUBROUTINE sort_wcc(values)
316 REAL(kind=dp), INTENT(INOUT) :: values(:)
317
318 INTEGER :: i, j
319 REAL(kind=dp) :: value
320
321 DO i = 2, SIZE(values)
322 value = values(i)
323 j = i - 1
324 DO WHILE (j >= 1)
325 IF (values(j) <= value) EXIT
326 values(j + 1) = values(j)
327 j = j - 1
328 END DO
329 values(j + 1) = value
330 END DO
331 END SUBROUTINE sort_wcc
332END MODULE topology_wilson
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.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
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...