Coverage for gpaw/test/corehole/test_sh2.py: 100%
133 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
1import pytest
2from ase.build import molecule
4import gpaw.mpi as mpi
5from gpaw import GPAW
6from gpaw.test import gen
7from gpaw.xas import XAS
10def folding_is_normalized(xas: XAS, dks, rel: float = 1e-5) -> bool:
11 _, ys_cn = xas.get_oscillator_strength(dks=dks)
13 ys_summed_c = ys_cn.sum(axis=1)
14 xf, yf_cn = xas.get_spectra(fwhm=0.5, dks=dks)
15 dxf = xf[1:] - xf[:-1]
16 assert dxf == pytest.approx(dxf[0])
17 yf_summed_c = yf_cn.sum(axis=1) * dxf[0]
19 return yf_summed_c == pytest.approx(ys_summed_c, rel=rel)
22@pytest.fixture
23def s1s1ch_name():
24 setupname = 'S1s1ch'
25 gen('S', name=setupname, corehole=(1, 0, 1), gpernode=30, write_xml=True)
26 return setupname
29@pytest.fixture
30def s2p1ch_name():
31 setupname = 'S2p1ch'
32 gen('S', name=setupname, corehole=(2, 1, 1), gpernode=30, write_xml=True)
33 return setupname
36def sh2(setupname):
37 atoms = molecule('SH2')
38 atoms.center(3)
40 nbands = 6
41 atoms.calc = GPAW(mode='fd', h=0.3, nbands=nbands,
42 setups={'S': setupname}, txt=None)
43 atoms.get_potential_energy()
45 return atoms
48@pytest.fixture
49def sh2_s1s1ch(s1s1ch_name):
50 return sh2(s1s1ch_name)
53@pytest.fixture
54def sh2_s2p1ch(s2p1ch_name):
55 return sh2(s2p1ch_name)
58def test_sulphur_2p_spin_io(in_tmp_dir, add_cwd_to_setup_paths, s2p1ch_name):
59 """Make sure this calculation does not fail
60 because of get_spin_contamination"""
61 atoms = molecule('SH2')
62 atoms.center(3)
64 atoms.set_initial_magnetic_moments([1, 0, 0])
65 atoms.calc = GPAW(mode='fd', h=0.3, spinpol=True,
66 setups={'S': s2p1ch_name}, txt=None,
67 convergence={
68 'energy': 0.1, 'density': 0.1, 'eigenstates': 0.1})
69 atoms.get_potential_energy()
72def test_sulphur_1s_xas_tp(in_tmp_dir, add_cwd_to_setup_paths, sh2_s1s1ch):
73 nbands = 6
74 nocc = 4 # for SH2
76 dks = 20
77 xas = XAS(sh2_s1s1ch.calc)
78 x, y_cn = xas.get_oscillator_strength(dks=dks)
79 assert y_cn.shape == (3, nbands - nocc)
80 assert x[0] == dks
81 assert xas.nocc == nocc
83 assert folding_is_normalized(xas, dks)
86def test_sulphur_1s_xas_XCH(in_tmp_dir, add_cwd_to_setup_paths, sh2_s1s1ch):
87 atoms = sh2_s1s1ch
89 nbands = 6
90 nocc = 4 # for SH2
91 dks = 20
93 calc = sh2_s1s1ch.calc.new(charge=-1)
94 atoms.calc = calc
96 atoms[0].magmom = 1
97 atoms.get_potential_energy()
99 xas = XAS(atoms.calc, relative_index_lumo=-1)
100 x, y_cn = xas.get_oscillator_strength(dks=dks)
101 assert xas.nocc == nocc
102 assert y_cn.shape == (3, nbands - nocc)
103 assert x[0] == dks
104 assert folding_is_normalized(xas, dks)
107def test_sulphur_2p_xas(in_tmp_dir, add_cwd_to_setup_paths, sh2_s2p1ch):
108 dks = 20
110 xas = XAS(sh2_s2p1ch.calc)
111 assert folding_is_normalized(xas, dks)
114def test_proj(in_tmp_dir, add_cwd_to_setup_paths, sh2_s1s1ch):
115 atoms = sh2_s1s1ch
117 dks = 20
118 xas0 = XAS(atoms.calc)
119 mefname = 'me.dat.npz'
120 proj = [[1, 0, 0]]
121 xas0.write(mefname)
122 x0, y0_cn = xas0.get_oscillator_strength(
123 dks=dks, proj=proj, proj_xyz=False)
124 x1, y1_cn = xas0.get_oscillator_strength(
125 dks=dks, proj_xyz=True)
127 xas1 = XAS().restart(mefname)
128 x0_1, y0_1_cn = xas1.get_oscillator_strength(
129 dks=dks, proj=proj, proj_xyz=False)
130 x1_1, y1_1_cn = xas1.get_oscillator_strength(
131 dks=dks, proj_xyz=True)
133 assert y1_cn.shape[0] == y0_cn.shape[0] + 2
134 assert y1_cn.shape[1] == y0_cn.shape[1]
135 assert x1 == pytest.approx(x0)
136 assert y1_cn[0] == pytest.approx(y0_cn[0])
138 assert x0 == pytest.approx(x0_1)
139 assert x1 == pytest.approx(x1_1)
140 assert y0_cn == pytest.approx(y0_1_cn)
141 assert y1_cn == pytest.approx(y1_1_cn)
144def test_parallel(in_tmp_dir, add_cwd_to_setup_paths, s2p1ch_name):
145 atoms = molecule('SH2')
146 atoms.center(3)
148 # serial calculation
149 fserial = f'serial_xas_rank{mpi.world.rank}.npz'
150 comm = mpi.world.new_communicator([mpi.world.rank])
151 print('serial, rank, size:', mpi.world.rank, comm.size)
152 atoms.calc = GPAW(mode='fd', h=0.3, setups={'S': s2p1ch_name},
153 txt=None, communicator=comm)
155 print('serial, atoms.calc.world.size:', atoms.calc.world.size)
156 atoms.get_potential_energy()
158 import time
159 t0 = time.time()
160 xas_s = XAS(atoms.calc)
161 xas_s.write(fserial)
162 t1 = time.time()
163 print(t1 - t0)
165 # parallel calculation
166 fparallel = 'parallel_xas.npz'
167 atoms.calc = GPAW(mode='fd', h=0.3, setups={'S': s2p1ch_name}, txt=None)
168 print('parallel, atoms.calc.world.size:', atoms.calc.world.size)
169 atoms.get_potential_energy()
171 t0 = time.time()
172 xas_p = XAS(atoms.calc)
173 xas_p.write(fparallel)
174 t1 = time.time()
175 print(t1 - t0)
177 dks = 20
178 xs, ys = xas_s.get_oscillator_strength(dks=dks)
179 xp, yp = xas_p.get_oscillator_strength(dks=dks)
181 assert xs == pytest.approx(xp)
182 assert ys == pytest.approx(yp)
184 assert xs == pytest.approx(xp)
185 assert ys == pytest.approx(yp)
188def test_io(in_tmp_dir, add_cwd_to_setup_paths, sh2_s1s1ch):
189 """Test that a direct calculation gives the same results as a calculation
190 restarted from matrix element file."""
191 dks = 20
192 medata = 'xasme.dat'
194 xas1 = XAS(sh2_s1s1ch.calc)
195 xas1.write(medata)
197 # define the XAS object by reading
198 xas2 = XAS().restart(medata)
200 x1, y1 = xas1.get_oscillator_strength(dks=dks)
201 x2, y2 = xas2.get_oscillator_strength(dks=dks)
202 assert x1 == pytest.approx(x2)
203 assert y1 == pytest.approx(y2)