Coverage for gpaw/test/response/test_chi0_intraband.py: 100%
57 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
1from functools import cached_property
2import numpy as np
3import pytest
5from gpaw.test import findpeak
6from gpaw.response.df import DielectricFunction
7from ase.units import Bohr, Hartree
10class Helper:
11 def __init__(self, gpw, integrationmode):
12 self._gpw = gpw
13 self._integrationmode = integrationmode
15 @cached_property
16 def df(self):
17 return DielectricFunction(
18 self._gpw,
19 frequencies={'type': 'nonlinear',
20 'domega0': 0.03},
21 ecut=10,
22 rate=0.1,
23 integrationmode=self._integrationmode,
24 txt=None)
26 @cached_property
27 def lfc(self):
28 # lfc == local field corrections (?)
29 return {axis: self.df.get_dielectric_function(direction=axis)[1]
30 for axis in 'xyz'}
32 @cached_property
33 def wp(self):
34 chi0_drude = self.df.chi0calc.chi0_opt_ext_calc.drude_calc.calculate(
35 self.df.chi0calc.chi0_opt_ext_calc.wd, 0.1)
36 return chi0_drude.plasmafreq_vv[0, 0]**0.5
38 @cached_property
39 def w_w(self):
40 return self.df.chi0calc.chi0_opt_ext_calc.wd.omega_w
42 def _compare_peak(self, calc, axis):
43 df1LFCx = self.lfc[axis]
44 df2LFCx = calc.lfc[axis]
45 # w_x equal for paired & polarized tetra
46 w1, I1 = findpeak(self.w_w, -(1. / df1LFCx).imag)
47 w2, I2 = findpeak(self.w_w, -(1. / df2LFCx).imag)
48 assert w1 == pytest.approx(w2, abs=1e-3)
49 assert I1 == pytest.approx(I2, abs=0.1)
51 def compare_peaks(self, calc):
52 for axis in 'xyz':
53 self._compare_peak(calc, axis)
56@pytest.mark.dielectricfunction
57@pytest.mark.tetrahedron
58@pytest.mark.response
59def test_chi0_intraband(in_tmp_dir, gpw_files):
60 """Comparing the plasmon peaks found in bulk sodium for two different
61 atomic structures. Testing for idential plasmon peaks. Not using
62 physical sodium cell."""
63 intraband_spinpaired = gpw_files['intraband_spinpaired_fulldiag']
64 intraband_spinpolarized = gpw_files['intraband_spinpolarized_fulldiag']
66 calc1 = Helper(intraband_spinpaired, 'tetrahedron integration')
67 calc2 = Helper(intraband_spinpaired, 'point integration')
68 calc3 = Helper(intraband_spinpolarized, 'tetrahedron integration')
69 calc4 = Helper(intraband_spinpolarized, 'point integration')
71 # Compare plasmon frequencies and intensities
72 w_w = calc1.w_w
74 # frequency grids must be the same
75 for calc in [calc1, calc2, calc3, calc4]:
76 assert np.allclose(calc.w_w, w_w, atol=1e-5, rtol=1e-4)
78 # Analytical Drude result
79 n = 1 / (calc1.df.gs.volume * Bohr**-3)
80 drude_wp = np.sqrt(4 * np.pi * n)
82 # From https://doi.org/10.1021/jp810808h
83 ref_wp = 5.71 / Hartree
85 # spin paired matches spin polar - tetra
86 assert calc1.wp == pytest.approx(calc3.wp, abs=1e-2)
87 # spin paired matches spin polar - none
88 assert calc2.wp == pytest.approx(calc4.wp, abs=1e-2)
89 # Use larger margin when comparing to Drude
90 assert calc1.wp == pytest.approx(drude_wp, abs=0.5)
91 # Use larger margin when comparing to Drude
92 assert calc2.wp == pytest.approx(drude_wp, abs=0.5)
93 # paired tetra match paper
94 assert calc1.wp == pytest.approx(ref_wp, abs=0.1)
95 # paired none match paper
96 assert calc2.wp == pytest.approx(ref_wp, abs=0.1)
98 # w_x, w_y and w_z equal for paired & polarized tetra
99 calc1.compare_peaks(calc3)
101 # w_x, w_y and w_z equal for paired & polarized none
102 calc2.compare_peaks(calc4)