9 USE iso_fortran_env,
ONLY: output_unit
20 REAL(kind=
dp),
PARAMETER :: pi = 3.1415926535897932384626433832795_dp, tolerance = 1.e-10_dp
25 CALL test_model(-1.0_dp, 1)
26 CALL test_model(-3.0_dp, 0)
27 CALL test_model(1.0_dp, 1)
28 CALL test_model(3.0_dp, 0)
33 CALL test_chern_checks()
34 WRITE (io_unit, *)
"Wilson-loop, Z2 and Chern unit tests passed."
44 REAL(KIND=
dp),
INTENT(IN) :: mass
45 INTEGER,
INTENT(IN) :: expected
47 INTEGER,
PARAMETER :: nline = 65, npoint = 41
49 COMPLEX(KIND=dp) :: h(2, 2), overlap(1, 1), PRODUCT(1, 1), &
50 states(2, npoint), work(8)
51 INTEGER :: i, invariant, j, line, status
52 REAL(KIND=
dp) :: berry, d, doubled(2, nline), &
53 eigenvalues(2), kx, ky, minimum_sv, &
54 rwork(4), wcc(1, nline), winding
57 ky = 2.0_dp*pi*real(line - 1,
dp)/real(nline - 1,
dp)
59 kx = 2.0_dp*pi*real(i - 1,
dp)/real(npoint,
dp)
60 d = mass + cos(kx) + cos(ky)
63 h(1, 2) = cmplx(sin(kx), -sin(ky),
dp)
64 h(2, 1) = conjg(h(1, 2))
65 CALL zheev(
'V',
'U', 2, h, 2, eigenvalues, work,
SIZE(work), rwork, status)
66 IF (status /= 0) error stop
"Chern model diagonalization failed"
67 states(:, i) = h(:, 1)
69 product(:, :) = 1.0_dp
71 j = mod(i, npoint) + 1
72 overlap(1, 1) = dot_product(states(:, i), states(:, j))
73 CALL wilson_step(product, overlap, minimum_sv, status, tolerance)
74 IF (status /= 0) error stop
"Chern model overlap is singular"
77 IF (status /= 0) error stop
"Chern model spectrum failed"
80 IF (status /= 0 .OR. invariant /= expected) error stop
"Incorrect model Chern number"
81 IF (abs(winding - real(expected,
dp)) > tolerance) error stop
"Incorrect Chern winding"
82 CALL chern_from_wcc(wcc(:, nline:1:-1), invariant, winding, status, tolerance)
83 IF (status /= 0 .OR. invariant /= -expected) error stop
"Chern orientation reversal failed"
84 doubled(1, :) = wcc(1, :)
85 doubled(2, :) = wcc(1, :)
86 CALL chern_from_wcc(doubled, invariant, winding, status, tolerance)
87 IF (status /= 0 .OR. invariant /= 2*expected) error stop
"Direct-sum Chern additivity failed"
93 SUBROUTINE test_chern_checks()
94 INTEGER :: invariant, status
95 REAL(KIND=
dp) :: surface(1, 5), winding
97 surface(1, :) = [0.0_dp, 0.1_dp, 0.2_dp, 0.3_dp, 0.4_dp]
98 CALL chern_from_wcc(surface, invariant, winding, status, tolerance)
99 IF (status /= -2) error stop
"Unclosed Chern surface was accepted"
100 surface(1, :) = [0.0_dp, 0.3_dp, 0.6_dp, 0.9_dp, 1.0_dp]
101 CALL chern_from_wcc(surface, invariant, winding, status, tolerance)
102 IF (status /= -3) error stop
"Unresolved Chern phase step was accepted"
103 surface(:, :) = 0.1_dp
104 CALL chern_from_wcc(surface, invariant, winding, status, tolerance)
105 IF (status /= 0 .OR. invariant /= 0) error stop
"Constant Chern surface was rejected"
106 END SUBROUTINE test_chern_checks
113 SUBROUTINE test_model(mass, expected)
114 REAL(KIND=
dp),
INTENT(IN) :: mass
115 INTEGER,
INTENT(IN) :: expected
117 INTEGER,
PARAMETER :: nline = 31, npoint = 41
119 COMPLEX(KIND=dp) :: gauged(2, 2), gauges(2, 2, npoint), links(2, 2, npoint), overlap(2, 2), &
120 PRODUCT(2, 2), reversed(2, 2), states(4, 2, npoint)
121 INTEGER :: i, invariant, j, line, status
122 REAL(KIND=
dp) :: berry, gauge_wcc(2, nline), kx, ky, &
123 minimum_sv, reverse_wcc(2, nline), &
127 ky = pi*real(line - 1,
dp)/real(nline - 1,
dp)
129 kx = 2.0_dp*pi*real(i - 1,
dp)/real(npoint,
dp)
130 CALL occupied_states(kx, ky, mass, states(:, :, i))
131 CALL gauge_matrix(kx, ky, gauges(:, :, i))
133 product(:, :) = 0.0_dp
134 product(1, 1) = 1.0_dp
135 product(2, 2) = 1.0_dp
136 gauged(:, :) = product
137 reversed(:, :) = product
139 j = mod(i, npoint) + 1
140 links(:, :, i) = matmul(conjg(transpose(states(:, :, i))), states(:, :, j))
141 CALL wilson_step(product, links(:, :, i), minimum_sv, status, tolerance)
142 IF (status /= 0) error stop
"BHZ overlap is singular"
143 overlap(:, :) = matmul(conjg(transpose(gauges(:, :, i))), &
144 matmul(links(:, :, i), gauges(:, :, j)))
145 CALL wilson_step(gauged, overlap, minimum_sv, status, tolerance)
146 IF (status /= 0) error stop
"Gauge-transformed BHZ overlap is singular"
149 overlap(:, :) = conjg(transpose(links(:, :, i)))
150 CALL wilson_step(reversed, overlap, minimum_sv, status, tolerance)
151 IF (status /= 0) error stop
"Reversed BHZ overlap is singular"
154 IF (status /= 0) error stop
"BHZ spectrum failed"
156 IF (status /= 0) error stop
"Gauge-transformed spectrum failed"
158 IF (status /= 0) error stop
"Reversed spectrum failed"
159 IF (
wcc_distance(wcc(:, line), gauge_wcc(:, line)) > tolerance)
THEN
160 error stop
"Wilson spectrum depends on occupied-space gauge"
162 IF (
wcc_distance(wcc(:, line), -reverse_wcc(:, line)) > tolerance)
THEN
163 error stop
"Loop reversal did not conjugate Wilson eigenvalues"
166 CALL z2_from_wcc(wcc, invariant, status, tolerance)
167 IF (status /= 0 .OR. invariant /= expected) error stop
"Incorrect BHZ Z2 invariant"
168 CALL z2_from_wcc(gauge_wcc, invariant, status, tolerance)
169 IF (status /= 0 .OR. invariant /= expected) error stop
"Gauge-dependent Z2 invariant"
170 CALL z2_from_wcc(reverse_wcc, invariant, status, tolerance)
171 IF (status /= 0 .OR. invariant /= expected) error stop
"Reversal-dependent Z2 invariant"
172 END SUBROUTINE test_model
181 SUBROUTINE occupied_states(kx, ky, mass, states)
182 REAL(KIND=
dp),
INTENT(IN) :: kx, ky, mass
183 COMPLEX(KIND=dp),
INTENT(OUT) :: states(4, 2)
185 COMPLEX(KIND=dp) :: h(4, 4), work(16)
187 REAL(KIND=
dp) :: d, eigenvalues(4), rwork(10)
189 d = mass + cos(kx) + cos(ky)
193 h(1, 2) = cmplx(sin(kx), -sin(ky),
dp)
194 h(2, 1) = conjg(h(1, 2))
197 h(3, 4) = cmplx(-sin(kx), -sin(ky),
dp)
198 h(4, 3) = conjg(h(3, 4))
199 CALL zheev(
'V',
'U', 4, h, 4, eigenvalues, work,
SIZE(work), rwork, status)
200 IF (status /= 0) error stop
"BHZ diagonalization failed"
201 states(:, :) = h(:, 1:2)
202 END SUBROUTINE occupied_states
210 SUBROUTINE gauge_matrix(kx, ky, matrix)
211 REAL(KIND=
dp),
INTENT(IN) :: kx, ky
212 COMPLEX(KIND=dp),
INTENT(OUT) :: matrix(2, 2)
214 COMPLEX(KIND=dp) :: determinant_phase, phase
215 REAL(KIND=
dp) :: angle
217 angle = 0.37_dp + 0.61_dp*sin(3.0_dp*kx + ky)
218 phase = exp(cmplx(0.0_dp, 0.73_dp*cos(kx - 2.0_dp*ky),
dp))
219 determinant_phase = exp(cmplx(0.0_dp, 0.29_dp*sin(kx + ky),
dp))
220 matrix(1, 1) = cos(angle)
221 matrix(1, 2) = sin(angle)*phase
222 matrix(2, 1) = -sin(angle)*conjg(phase)
223 matrix(2, 2) = cos(angle)
224 matrix(:, 1) = matrix(:, 1)*determinant_phase
225 END SUBROUTINE gauge_matrix
230 SUBROUTINE test_checks()
231 COMPLEX(KIND=dp) :: overlap(2, 2), PRODUCT(2, 2)
232 INTEGER :: invariant, status
233 REAL(KIND=
dp) :: berry, minimum_sv, surface(2, 3), wcc(2)
235 product(:, :) = 0.0_dp
236 product(1, 1) = 1.0_dp
237 product(2, 2) = 1.0_dp
238 overlap(:, :) = 0.0_dp
239 CALL wilson_step(product, overlap, minimum_sv, status, tolerance)
240 IF (status /= -2) error stop
"Singular overlap was accepted"
242 overlap(1, 1) = 0.8_dp*exp(cmplx(0.0_dp, 0.2_dp*pi,
dp))
243 overlap(2, 2) = 0.6_dp*exp(cmplx(0.0_dp, 0.6_dp*pi,
dp))
244 CALL wilson_step(product, overlap, minimum_sv, status, tolerance)
245 IF (status /= 0 .OR. abs(minimum_sv - 0.6_dp) > tolerance)
THEN
246 error stop
"Polar factor singular value is incorrect"
249 IF (status /= 0) error stop
"Analytic spectrum failed"
250 IF (
wcc_distance(wcc, [0.1_dp, 0.3_dp]) > tolerance) error stop
"Incorrect analytic WCC"
251 IF (abs(berry - 0.8_dp*pi) > tolerance) error stop
"Incorrect analytic Berry phase"
256 CALL z2_from_wcc(surface, invariant, status, tolerance)
257 IF (status /= -2 .OR. invariant /= -1) error stop
"Missing Kramers pairs were accepted"
258 surface(:, :) = 0.1_dp
259 surface(:, 2) = 0.6_dp
261 surface(:, :) = 0.1_dp
262 IF (.NOT.
surface_resolved(surface)) error stop
"Constant surface was rejected"
263 CALL z2_from_wcc(surface, invariant, status, tolerance)
264 IF (status /= 0 .OR. invariant /= 0) error stop
"Incorrect constant-surface parity"
265 IF (
wcc_distance([0.99_dp, 0.2_dp], [0.2_dp, -0.01_dp]) > tolerance)
THEN
266 error stop
"Circular WCC matching failed"
268 END SUBROUTINE test_checks
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...
subroutine test_chern_model(mass, expected)
Known first Chern numbers of the occupied two-band lattice Dirac model.
program topology_wilson_unittest