Coverage for gpaw/test/test_berryphase.py: 100%
60 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-08 00:17 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-08 00:17 +0000
1import numpy as np
2import pytest
4import gpaw.mpi as mpi
5from gpaw import GPAW
6from gpaw.berryphase import (get_berry_phases,
7 polarization_phase,
8 parallel_transport)
10# Values from an earlier test
11ref_phi_mos2_km = np.array(
12 [[2.72907676e-04, 2.99369724e+00, 4.51932187e+00, 5.94725651e+00],
13 [4.84334561e-03, 2.42519044e+00, 4.43335136e+00, 5.75115262e+00],
14 [2.99682618e-02, 2.26119678e+00, 4.30480687e+00, 5.78042986e+00],
15 [4.84334561e-03, 2.42519044e+00, 4.43335136e+00, 5.75115262e+00],
16 [2.72907676e-04, 2.99369724e+00, 4.51932187e+00, 5.94725651e+00],
17 [3.75847658e-03, 2.67197983e+00, 4.36511629e+00, 5.60446187e+00]])
20def test_parallel_transport_mos2(in_tmp_dir, gpw_files):
21 # Calculate the berry phases and spin projections
22 gpw = gpw_files['mos2_pw_nosym']
23 parallel_transport(str(gpw), name='mos2', scale=1)
25 # Load phase-ordered data
26 phi_km, S_km = load_renormalized_data('mos2')
28 # Test that the berry phases do not change (assuming that they
29 # were correct to begin with)
30 print(phi_km[:, ::7]) # we slice the bands to make output readable
31 assert phi_km[:, ::7] == pytest.approx(ref_phi_mos2_km, abs=0.05)
34def test_parallel_transport_i2sb2(in_tmp_dir, gpw_files):
35 # Calculate the berry phases and spin projections
36 calc = GPAW(gpw_files['i2sb2_pw_nosym'], txt=None,
37 communicator=mpi.serial_comm)
38 nelec = int(calc.get_number_of_electrons())
39 parallel_transport(calc, name='i2sb2', scale=1,
40 # To calculate the valence bands berry
41 # phases, we only need the top valence
42 # group of bands. This corresponds to 2x8
43 # bands, see c2db (x2 for spin)
44 bands=range(nelec - 2 * 8, nelec))
46 # Load phase-ordered data
47 phi_km, S_km = load_renormalized_data('i2sb2')
49 # # For the spin test below to make sense, please compare this
50 # # plot to the berry phase plot at the c2db website
51 # import matplotlib.pyplot as plt
52 # plt.scatter(np.tile(np.arange(len(phi_km)), len(phi_km.T)),
53 # phi_km.T.reshape(-1),
54 # cmap=plt.get_cmap('viridis'),
55 # c=S_km.T.reshape(-1),
56 # s=25,
57 # marker='o')
58 # plt.ylim((0, 2 * np.pi))
59 # plt.show()
61 # We test the spin for bands we are in control of, that is,
62 # avoid high-symmetry points and look only at the winding
63 # bands above a phase of ~pi, see the c2db berry phase plot
64 bands = [0, 1, 3, 4]
65 phi_qm = phi_km[bands]
66 S_qm = S_km[bands]
67 Svalues = S_qm[phi_qm > 3.0]
68 assert Svalues == pytest.approx(np.array([-1, 1, # k=0
69 -1, 1, # k=1
70 1, -1, # k=2
71 1, -1]), # k=3
72 abs=0.01)
73 # Test also the berry phases for the same bands
74 phivalues = phi_qm[phi_qm > 3.0]
75 print(phivalues)
76 # We test that the values don't change too much. This will
77 # also guarantee that the results agree qualitatively with
78 # the c2db plot
79 assert phivalues == pytest.approx([3.115, 5.309, 3.970, 4.455,
80 3.970, 4.455, 3.115, 5.309], abs=0.05)
83def load_renormalized_data(name):
84 data = np.load(f'phases_{name}.npz')
85 phi_km = data['phi_km']
86 S_km = data['S_km']
88 # Phases are only well-defined modulo 2pi
89 phi_km %= 2 * np.pi
91 # Sort bands by the berry phase
92 indices = np.argsort(phi_km, axis=1)
93 phi_km = np.take_along_axis(phi_km, indices, axis=1)
94 S_km = np.take_along_axis(S_km, indices, axis=1)
96 return phi_km, S_km
99def test_polarization_phase(in_tmp_dir, gpw_files):
100 pi2 = 2.0 * np.pi
101 phases_c = polarization_phase(gpw_files['mos2_pw_nosym'],
102 comm=mpi.world)
104 phases_t = {
105 'phase_c': pi2 * np.array([8.66037602, 3.33962524, 8.54861146e-15]),
106 'electronic_phase_c': pi2 * np.array([0.66037602, -0.66037476, 1.0]),
107 'atomic_phase_c': pi2 * np.array([8.0, 4.0, 13.0]),
108 'dipole_phase_c': pi2
109 * np.array([7.23912394e-01, -7.23912423e-01, 8.54861146e-15])}
111 # test all components
112 # apply modulo
113 for key in phases_c:
114 # only should test modulo 2pi
115 dphi = phases_c[key] - phases_t[key]
116 phases_c[key] -= np.rint(dphi / pi2) * pi2
117 print(key)
118 assert phases_c[key] == pytest.approx(phases_t[key], abs=1e-6)
121def test_berry_phases(in_tmp_dir, gpw_files):
122 calc = GPAW(gpw_files['mos2_pw_nosym'], communicator=mpi.serial_comm)
124 ind, phases = get_berry_phases(calc)
126 indtest = np.array([[0, 6, 12, 18, 24, 30],
127 [1, 7, 13, 19, 25, 31],
128 [2, 8, 14, 20, 26, 32],
129 [3, 9, 15, 21, 27, 33],
130 [4, 10, 16, 22, 28, 34],
131 [5, 11, 17, 23, 29, 35]])
133 phasetest = [1.66179, 2.54985, 3.10069, 2.54985, 1.66179, 0.92385]
134 assert ind == pytest.approx(indtest)
135 assert phases == pytest.approx(phasetest, abs=1e-3)
138# only master will raise, so this test will hang in parallel
139@pytest.mark.serial
140def test_assertions(in_tmp_dir, gpw_files):
141 """
142 Functions should only work without symmetry
143 Tests so that proper assertion is raised for calculator
144 with symmetry enabled
145 """
147 gpw_file = gpw_files['mos2_pw']
148 with pytest.raises(AssertionError):
149 polarization_phase(gpw_file, comm=mpi.serial_comm)
151 calc = GPAW(gpw_file, communicator=mpi.serial_comm)
153 with pytest.raises(AssertionError):
154 ind, phases = get_berry_phases(calc)
156 with pytest.raises(AssertionError):
157 phi_km, S_km = parallel_transport(calc, direction=0,
158 name='mos2', scale=0)