19 COMPLEX(dp) :: b(4, 4), h(4, 4), h2(4, 4), j(4, 4, 3), j2(4, 4, 3), norm(3, 3), norm2(3, 3), &
20 s(4, 4), s2(4, 4), x(4, 4, 3), x2(4, 4, 3)
21 INTEGER :: a, c, i, status
22 REAL(
dp) :: e(4), e2(4)
33 h(1, 2) = cmplx(0.0_dp, 0.3_dp,
dp)
34 h(2, 1) = conjg(h(1, 2))
35 h(3, 4) = conjg(h(1, 2))
45 x(:, :, 3) = 2*x(:, :, 1) - x(:, :, 2)
47 IF (status /= 0) error stop
'Spinor current failed'
48 IF (maxval(abs(e - [-0.1_dp, -0.1_dp, 0.9_dp, 0.9_dp])) > 1.e-12_dp) error stop
'Spinor spectrum failed'
50 IF (maxval(abs(j(:, :, a) + conjg(transpose(j(:, :, a))))) > 1.e-12_dp) error stop
'Current is not anti-Hermitian'
52 norm(a, c) = sum(conjg(j(:, :, a))*j(:, :, c))
55 IF (abs(norm(1, 1) - 4.0_dp) > 1.e-12_dp) error stop
'Analytic current strength failed'
60 b(3, 1) = cmplx(0.2_dp, 0.4_dp,
dp)
61 b(1, 4) = cmplx(-0.3_dp, 0.1_dp,
dp)
63 h2 = matmul(conjg(transpose(b)), matmul(h, b))
64 s2 = matmul(conjg(transpose(b)), b)
66 x2(:, :, a) = matmul(conjg(transpose(b)), matmul(x(:, :, a), b)) + real(a,
dp)*s2
69 IF (status /= 0 .OR. maxval(abs(e - e2)) > 1.e-12_dp) error stop
'Nonorthogonal current spectrum failed'
72 norm2(a, c) = sum(conjg(j2(:, :, a))*j2(:, :, c))
75 IF (maxval(abs(norm - norm2)) > 1.e-11_dp) error stop
'Basis/origin/gauge invariance failed'
78 IF (status /= -2) error stop
'Indefinite overlap accepted'
82 IF (status /= -1) error stop
'Non-Hermitian position accepted'
83 print *,
'Projected spinor current, metric and gauge tests passed.'
95 COMPLEX(dp),
PARAMETER :: iu = (0.0_dp, 1.0_dp)
97 COMPLEX(dp) :: b(2, 2), d(2, 2, 3), d2(2, 2, 3), db(2, 2), dh(2, 2, 3), dh2(2, 2, 3), &
98 ds(2, 2, 3), ds2(2, 2, 3), expected(2, 2), frame(2, 2), h(2, 2), h2(2, 2), j(2, 2, 3), &
99 j2(2, 2, 3), s(2, 2), s2(2, 2)
100 INTEGER :: i, ik, status
101 REAL(
dp) :: e(2), e2(2), k, residuals(2), root, &
102 shift, speed, strength, strength2
110 h(1, 1) = h(1, 1) + 0.3_dp
111 h(2, 2) = h(2, 2) - 0.3_dp
112 h(1, 2) = 0.4_dp*sin(k) - iu*0.2_dp*cos(k)
113 h(2, 1) = conjg(h(1, 2))
116 dh(1, 2, 1) = 0.4_dp*cos(k) + iu*0.2_dp*sin(k)
117 dh(2, 1, 1) = conjg(dh(1, 2, 1))
121 IF (status /= 0) error stop
'Bloch current failed'
122 CALL bloch_current_from_frame(h, s, dh, ds, d, e, frame, j2, 1.e-9_dp, residuals, status)
123 IF (status /= 0 .OR. maxval(abs(j2 - j)) > 1.e-12_dp) error stop
'Reused eigenframe failed'
124 CALL bloch_current_from_frame(h, s, dh, ds, d, e + 0.1_dp, frame, j2, 1.e-9_dp, residuals, status)
125 IF (status /= -4) error stop
'Wrong frame eigenvalues accepted'
126 CALL bloch_current_from_frame(h, s, dh, ds, d, e, 1.1_dp*frame, j2, 1.e-9_dp, residuals, status)
127 IF (status /= -4) error stop
'Nonorthonormal frame accepted'
128 root = sqrt(0.09_dp + 0.16_dp*sin(k)**2 + 0.04_dp*cos(k)**2)
129 IF (maxval(abs(e - [k*k - root, k*k + root])) > 1.e-12_dp) error stop
'Analytic bands failed'
130 speed = 0.12_dp*sin(k)*cos(k)/root
131 IF (abs(iu*j(1, 1, 1) - (2*k - speed)) > 1.e-12_dp) error stop
'Lower band velocity failed'
132 IF (abs(iu*j(2, 2, 1) - (2*k + speed)) > 1.e-12_dp) error stop
'Upper band velocity failed'
133 IF (maxval(abs(j(:, :, 1) + conjg(transpose(j(:, :, 1))))) > 1.e-12_dp)
THEN
134 error stop
'Bloch current not anti-Hermitian'
140 db(2, 1) = cmplx(0.17_dp, 0.23_dp,
dp)
141 db(1, 2) = cmplx(-0.09_dp, 0.11_dp,
dp)
143 h2 = matmul(conjg(transpose(b)), matmul(h, b))
144 s2 = matmul(conjg(transpose(b)), b)
148 dh2(:, :, 1) = matmul(conjg(transpose(b)), matmul(dh(:, :, 1), b)) + &
149 matmul(conjg(transpose(db)), matmul(h, b)) + matmul(conjg(transpose(b)), matmul(h, db))
150 ds2(:, :, 1) = matmul(conjg(transpose(db)), b) + matmul(conjg(transpose(b)), db)
151 d2(:, :, 1) = -iu*matmul(conjg(transpose(db)), b) + 7*s2
153 IF (status /= 0 .OR. maxval(abs(e - e2)) > 1.e-12_dp) error stop
'Bloch basis covariance failed'
155 IF (abs(j(i, i, 1) - j2(i, i, 1)) > 1.e-11_dp) error stop
'Band velocity basis dependence'
157 IF (maxval(abs(abs(j) - abs(j2))) > 1.e-11_dp) error stop
'Interband velocity gauge dependence'
160 CALL bloch_current(h2 + shift*s2, s2, dh2 + shift*ds2, ds2, d2, e2, j2, status)
161 IF (status /= 0 .OR. maxval(abs(e + shift - e2)) > 1.e-11_dp) error stop
'Energy shift failed'
162 IF (maxval(abs(abs(j) - abs(j2))) > 1.e-10_dp) error stop
'Velocity energy-zero dependence'
165 IF (status /= -3) error stop
'Inconsistent connection accepted'
174 IF (status /= 0) error stop
'Finite Bloch limit failed'
176 IF (status /= 0 .OR. maxval(abs(j - j2)) > 1.e-12_dp) error stop
'Finite commutator limit failed'
186 IF (status /= 0) error stop
'Degenerate Bloch block failed'
187 strength = sum(abs(j(:, :, 1))**2)*(-
fermi_slope(0.0_dp, 0.0_dp, 0.0_dp, 0.1_dp))
188 IF (abs(strength - 10.0_dp) > 1.e-12_dp) error stop
'Intraband Drude weight failed'
189 b = reshape([iu, (1.0_dp, 0.0_dp), (1.0_dp, 0.0_dp), iu], [2, 2])/sqrt(2.0_dp)
190 expected = matmul(conjg(transpose(b)), matmul(dh(:, :, 1), b))
191 dh(:, :, 1) = expected
193 strength2 = sum(abs(j(:, :, 1))**2)*(-
fermi_slope(0.0_dp, 0.0_dp, 0.0_dp, 0.1_dp))
194 IF (status /= 0 .OR. abs(strength - strength2) > 1.e-12_dp) error stop
'Degenerate response gauge failed'
195 IF (abs(
fermi_slope(1.e-9_dp, -1.e-9_dp, 0.0_dp, 0.1_dp) + 2.5_dp) > 1.e-12_dp)
THEN
196 error stop
'Fermi near-degeneracy limit failed'
198 IF (abs(
fermi_slope(0.1_dp, -0.1_dp, 0.0_dp, 0.1_dp) + tanh(0.5_dp)/0.2_dp) > 1.e-12_dp)
THEN
199 error stop
'Fermi divided difference failed'
201 print *,
'Bloch metric/connection, band velocity, gauge, degeneracy and Drude tests passed.'
208 USE ieee_arithmetic,
ONLY: ieee_quiet_nan, &
216 COMPLEX(dp),
PARAMETER :: iu = (0.0_dp, 1.0_dp)
217 REAL(
dp),
PARAMETER :: pi = 3.1415926535897932384626433832795_dp
218 REAL(
dp) :: energies(4), hall(3, 3),
check(3, 3), reference(3, 3), rotation(3, 3)
219 REAL(
dp) :: analytic, error, gauge_error, mass, kx, ky, radius, omega, integrated, curvature,
gamma
220 REAL(
dp) :: e2(2), masses(3), expected(3), unit(3)
221 COMPLEX(dp) :: current(4, 4, 3), changed(4, 4, 3), u(4, 4)
222 COMPLEX(dp) :: h2(2, 2), s2(2, 2), dh2(2, 2, 3), ds2(2, 2, 3), d2(2, 2, 3), j2(2, 2, 3)
223 INTEGER :: a, b, i, j, imass, ix, iy, status
224 INTEGER,
PARAMETER :: mesh = 48
230 j2(1, 2, 2) = -1.0_dp
232 CALL hall_response([-0.7_dp, 0.7_dp], j2, 0.0_dp, 0.2_dp, 0.3_dp, hall, status)
233 analytic = 2.0_dp*tanh(0.7_dp/0.4_dp)/(1.4_dp**2 + 0.3_dp**2)
234 IF (status /= 0 .OR. abs(hall(1, 2) - analytic) > 1.e-13_dp) error stop
'Two-level Hall sign or scale'
235 IF (maxval(abs(hall + transpose(hall))) /= 0.0_dp) error stop
'Hall not antisymmetric'
236 CALL hall_response([0.0_dp, 0.0_dp], j2, 0.0_dp, 0.2_dp, 0.3_dp, hall, status)
237 IF (status /= 0 .OR. maxval(abs(hall)) /= 0.0_dp) error stop
'Degenerate Hall block'
239 radius = 10.0_dp**(-i)
240 CALL hall_response([-radius, radius], j2, 0.0_dp, 0.2_dp, 0.3_dp, hall, status)
241 analytic = 2.0_dp*tanh(radius/0.4_dp)/(4*radius**2 + 0.3_dp**2)
242 IF (status /= 0 .OR. abs(hall(1, 2)/analytic - 1.0_dp) > 1.e-12_dp)
THEN
243 error stop
'Near-degenerate Hall limit'
247 energies = [-0.9_dp, -0.9_dp, 0.8_dp, 0.8_dp]
251 current(i, j, a) = cmplx(sin(real(i + 3*j + a,
dp)), cos(real(2*i - j + a,
dp)),
dp)
254 current(:, :, a) = current(:, :, a) - conjg(transpose(current(:, :, a)))
256 CALL hall_response(energies, current, 0.1_dp, 0.15_dp, 0.07_dp, hall, status)
257 IF (status /= 0 .OR. maxval(abs(hall)) < 0.1_dp) error stop
'Nontrivial four-band response'
258 CALL liouville_reference(energies, current, 0.1_dp, 0.15_dp, 0.07_dp, reference)
259 error = maxval(abs(hall - 0.5_dp*(reference - transpose(reference))))
260 IF (error > 2.e-12_dp) error stop
'Full Liouvillian reference mismatch'
261 print
'(A,ES14.6)',
'Hall Liouvillian residual: ', error
265 IF (dot_product(unit, matmul(reference, unit)) < -1.e-12_dp) error stop
'Dissipation sign'
269 u(1:2, 1:2) = reshape([iu, (1.0_dp, 0.0_dp), (1.0_dp, 0.0_dp), iu], [2, 2])/sqrt(2.0_dp)
270 u(3:4, 3:4) = reshape([(0.6_dp, 0.0_dp), (0.0_dp, 0.8_dp), (0.0_dp, 0.8_dp), &
271 (0.6_dp, 0.0_dp)], [2, 2])
273 changed(:, :, a) = matmul(conjg(transpose(u)), matmul(current(:, :, a), u))
276 IF (status /= 0 .OR. maxval(abs(hall -
check)) > 2.e-12_dp) error stop
'Degenerate gauge covariance'
277 CALL hall_response(energies + 2.3_dp, current, 2.4_dp, 0.15_dp, 0.07_dp,
check, status)
278 IF (status /= 0 .OR. maxval(abs(hall -
check)) > 2.e-12_dp) error stop
'Energy zero covariance'
279 changed = current([3, 1, 4, 2], [3, 1, 4, 2], :)
280 CALL hall_response(energies([3, 1, 4, 2]), changed, 0.1_dp, 0.15_dp, 0.07_dp,
check, status)
281 IF (status /= 0 .OR. maxval(abs(hall -
check)) > 2.e-12_dp) error stop
'Band permutation covariance'
283 IF (status /= 0 .OR. maxval(abs(hall +
check)) > 2.e-12_dp) error stop
'Time-reversed Hall sign'
284 rotation = reshape([0.6_dp, 0.8_dp, 0.0_dp, -0.8_dp, 0.6_dp, 0.0_dp, &
285 0.0_dp, 0.0_dp, -1.0_dp], [3, 3])
289 changed(:, :, a) = changed(:, :, a) + rotation(a, b)*current(:, :, b)
293 reference = matmul(rotation, matmul(hall, transpose(rotation)))
294 IF (status /= 0 .OR. maxval(abs(reference -
check)) > 2.e-12_dp) error stop
'Cartesian tensor covariance'
297 IF (status == 0) error stop
'Zero temperature accepted'
299 IF (status == 0) error stop
'Zero relaxation accepted'
300 CALL hall_response(energies, current, ieee_value(0.0_dp, ieee_quiet_nan), 0.1_dp, 0.1_dp,
check, status)
301 IF (status == 0) error stop
'NaN chemical potential accepted'
303 changed(1, 2, 1) = changed(1, 2, 1) + 0.1_dp
305 IF (status == 0) error stop
'Non-anti-Hermitian current accepted'
309 masses = [-1.0_dp, 1.0_dp, 3.0_dp]
310 expected = [-1.0_dp, 1.0_dp, 0.0_dp]
324 ky = 2*pi*real(iy,
dp)/mesh
326 kx = 2*pi*real(ix,
dp)/mesh
327 h2(1, 1) = mass + cos(kx) + cos(ky)
329 h2(1, 2) = sin(kx) - iu*sin(ky)
330 h2(2, 1) = conjg(h2(1, 2))
332 dh2(1, 1, 1) = -sin(kx)
333 dh2(2, 2, 1) = sin(kx)
334 dh2(1, 2, 1) = cos(kx)
335 dh2(2, 1, 1) = cos(kx)
336 dh2(1, 1, 2) = -sin(ky)
337 dh2(2, 2, 2) = sin(ky)
338 dh2(1, 2, 2) = -iu*cos(ky)
339 dh2(2, 1, 2) = iu*cos(ky)
341 IF (status /= 0) error stop
'Chern-model Bloch current'
343 IF (status /= 0) error stop
'Chern-model Hall kernel'
344 radius = sqrt(sin(kx)**2 + sin(ky)**2 + (mass + cos(kx) + cos(ky))**2)
345 omega = (cos(kx) + cos(ky) + mass*cos(kx)*cos(ky))/(2*radius**3)
346 analytic = -omega*4*radius**2/(4*radius**2 +
gamma**2)*tanh(radius/0.02_dp)
347 error = max(error, abs(
check(1, 2) - analytic))
349 gauge_error = max(gauge_error, maxval(abs(
check - reference)))
350 integrated = integrated +
check(1, 2)*2*pi/mesh**2
351 curvature = curvature + omega*2*pi/mesh**2
354 IF (error > 1.e-12_dp) error stop
'Analytic Berry-curvature response mismatch'
355 IF (abs(integrated - expected(imass)) > 1.e-6_dp) error stop
'Chern Hall limit'
356 IF (abs(curvature + expected(imass)) > 1.e-10_dp) error stop
'Independent Chern integral'
357 IF (gauge_error > 1.e-12_dp) error stop
'Nonorthogonal AO Hall covariance'
358 print
'(A,F5.1,3ES18.10)',
'Hall Chern model mass, sigma, Chern, residual: ', mass, integrated, curvature, error
359 print
'(A,ES14.6)',
'Hall k-dependent nonorthogonal AO residual: ', gauge_error
361 print *,
'Hall sign, Liouvillian, gauge, time reversal, degeneracy and Chern tests passed.'
373 REAL(dp),
INTENT(IN) :: kx, ky
374 COMPLEX(dp),
INTENT(IN) :: h(2, 2), dh(2, 2, 3)
375 REAL(dp),
INTENT(IN) :: gamma
376 REAL(dp),
INTENT(OUT) :: hall(3, 3)
378 COMPLEX(dp) :: basis(2, 2), db(2, 2, 3), dhx(2, 2, 3), &
379 dsx(2, 2, 3), dx(2, 2, 3), hx(2, 2), &
380 jx(2, 2, 3), sx(2, 2)
385 basis(1, 1) = 1.1_dp + 0.1_dp*cos(kx)
386 basis(2, 2) = 0.9_dp + 0.1_dp*sin(ky)
387 basis(1, 2) = 0.13_dp*exp(iu*(kx + ky))
388 basis(2, 1) = 0.07_dp*exp(iu*(2*kx - ky))
390 db(1, 1, 1) = -0.1_dp*sin(kx)
391 db(2, 2, 2) = 0.1_dp*cos(ky)
392 db(1, 2, 1:2) = iu*basis(1, 2)
393 db(2, 1, 1) = 2*iu*basis(2, 1)
394 db(2, 1, 2) = -iu*basis(2, 1)
395 hx = matmul(conjg(transpose(basis)), matmul(h, basis))
396 sx = matmul(conjg(transpose(basis)), basis)
398 dhx(:, :, a) = matmul(conjg(transpose(basis)), matmul(dh(:, :, a), basis)) + &
399 matmul(conjg(transpose(db(:, :, a))), matmul(h, basis)) + &
400 matmul(conjg(transpose(basis)), matmul(h, db(:, :, a)))
401 dsx(:, :, a) = matmul(conjg(transpose(db(:, :, a))), basis) + &
402 matmul(conjg(transpose(basis)), db(:, :, a))
403 dx(:, :, a) = -iu*matmul(conjg(transpose(db(:, :, a))), basis) + real(a, dp)*sx
406 IF (status /= 0) error stop
'Nonorthogonal AO Chern model'
408 IF (status /= 0) error stop
'Nonorthogonal AO Hall kernel'
420 SUBROUTINE liouville_reference(e, currents, mu, kt, gamma, sigma)
421 REAL(dp),
INTENT(IN) :: e(4)
422 COMPLEX(dp),
INTENT(IN) :: currents(4, 4, 3)
423 REAL(dp),
INTENT(IN) :: mu, kt, gamma
424 REAL(dp),
INTENT(OUT) :: sigma(3, 3)
426 COMPLEX(dp) :: basis(4, 4), drive(4, 4), h(4, 4), &
427 liouvillian(16, 16), response(4, 4), &
428 rhs(16, 3), trace, v(4, 4, 3)
429 INTEGER :: a, b, column, i, info, j, k, l, &
434 basis(i, j) = exp(iu*2*pi*real((i - 1)*(j - 1), dp)/4)/2
441 h = matmul(basis, matmul(h, conjg(transpose(basis))))
443 v(:, :, a) = matmul(basis, matmul(iu*currents(:, :, a), conjg(transpose(basis))))
446 drive(i, j) =
fermi_slope(e(i), e(j), mu, kt)*iu*currents(i, j, a)
449 drive = matmul(basis, matmul(drive, conjg(transpose(basis))))
450 rhs(:, a) = reshape(drive, [16])
456 liouvillian(row, row) =
gamma
459 column = k + 4*(l - 1)
460 IF (j == l) liouvillian(row, column) = liouvillian(row, column) + iu*h(i, k)
461 IF (i == k) liouvillian(row, column) = liouvillian(row, column) - iu*h(l, j)
466 CALL zgesv(16, 3, liouvillian, 16, pivot, rhs, 16, info)
467 IF (info /= 0) error stop
'Liouvillian solve failed'
469 response = reshape(rhs(:, b), [4, 4])
471 trace = sum(v(:, :, a)*transpose(response))
472 sigma(a, b) = -real(trace, dp)
475 END SUBROUTINE liouville_reference