Coverage for gpaw/test/sic/test_pwsic.py: 90%
49 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-20 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-20 00:19 +0000
1import io
2import pytest
4from gpaw import GPAW, restart
5import numpy as np
6from ase.dft.bandgap import bandgap
7from ase.units import Ha
9import numpy.testing as npt
10from gpaw.io.logger import GPAWLogger
11from gpaw.wavefunctions.base import eigenvalue_string
12from gpaw.test.sic._utils import (mk_arr_from_str,
13 extract_lagrange_section,
14 MockWorld)
15from gpaw.mpi import rank
18@pytest.mark.old_gpaw_only
19@pytest.mark.sic
20def test_pwsic(in_tmp_dir, gpw_files):
21 """
22 test Perdew-Zunger Self-Interaction
23 Correction in PW mode using DirectMin
24 :param in_tmp_dir:
25 :return:
26 """
27 calc = GPAW(gpw_files["h2o_pwsic"])
28 H2O = calc.atoms
29 H2O.calc = calc
30 e = H2O.get_potential_energy()
31 f = H2O.get_forces()
32 efermi = calc.wfs.fermi_levels[0] * Ha
33 gap = bandgap(calc, efermi=efermi)[0]
35 # Numeric forces, generated by disabled code below
36 f2 = np.array(
37 [
38 [0.22161312, -0.98564396, -0.00204214],
39 [-0.34986867, 0.17494903, 0.00029861],
40 [0.01085528, 0.56112341, 0.00129632],
41 ]
42 )
43 assert f2 == pytest.approx(f, abs=3e-2)
44 assert e == pytest.approx(-9.98919, abs=1e-3)
45 assert gap == pytest.approx(9.555, abs=1e-2)
47 numeric = False
48 if numeric:
49 from gpaw.test import calculate_numerical_forces
51 f_num = calculate_numerical_forces(H2O, 0.001)
52 print("Numerical forces")
53 print(f_num)
54 print(f - f_num, np.abs(f - f_num).max())
56 #
57 calc.write("h2o.gpw", mode="all")
59 H2O, calc = restart("h2o.gpw", txt="-")
60 H2O.positions += 1.0e-6
61 f3 = H2O.get_forces()
62 niter = calc.get_number_of_iterations()
63 assert niter == pytest.approx(4, abs=3)
64 assert f2 == pytest.approx(f3, abs=3e-2)
66 if rank == 0:
67 logger = GPAWLogger(MockWorld(rank=0))
68 string_io = io.StringIO()
69 logger.fd = string_io
70 calc.wfs.summary_func(logger)
71 lstr = extract_lagrange_section(string_io.getvalue())
73 expect_lagrange_str = """\
74 Band L_ii Occupancy Band L_ii Occupancy
75 0 -21.28876 1.00000 0 -21.29052 1.00000
76 1 -21.02682 1.00000 1 -21.03380 1.00000
77 2 -13.96149 1.00000 2 -13.94529 1.00000
78 3 -13.91558 1.00000 3 -13.92438 1.00000
79 4 -0.94710 0.00000 4 -0.94712 0.00000
80 5 0.76805 0.00000 5 0.76806 0.00000
81 """
82 expect_eigen_str = """\
83 Band Eigenvalues Occupancy Eigenvalues Occupancy
84 0 -30.18943 1.00000 -30.19005 1.00000
85 1 -16.73073 1.00000 -16.73110 1.00000
86 2 -12.77049 1.00000 -12.77136 1.00000
87 3 -10.50200 1.00000 -10.50147 1.00000
88 4 -0.94720 0.00000 -0.94720 0.00000
89 5 0.76815 0.00000 0.76815 0.00000
90 """
92 npt.assert_allclose(
93 mk_arr_from_str(expect_lagrange_str, 6),
94 mk_arr_from_str(lstr, 6),
95 atol=0.3,
96 )
98 npt.assert_allclose(
99 mk_arr_from_str(expect_eigen_str, 5),
100 mk_arr_from_str(eigenvalue_string(calc.wfs), 5, skip_rows=1),
101 atol=0.3,
102 )