Coverage for gpaw/utilities/ekin.py: 18%
50 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
1from math import pi
2from typing import Tuple
3import numpy as np
4from ase.units import Ha
6from gpaw.typing import Array1D
7from gpaw.setup import Setup
10def ekin(dataset: Setup) -> Tuple[Array1D, Array1D, float]:
11 """Calculate PAW kinetic energy contribution as a function of G."""
12 ds = dataset
13 rgd = dataset.rgd
14 de_j = ds.data.e_kin_jj.diagonal()
15 phit_j = ds.pseudo_partial_waves_j
16 e0 = -ds.Kc
17 e_k: Array1D = 0.0 # type: ignore
19 for f, l, de, phit in zip(ds.f_j, ds.l_j, de_j, phit_j):
20 if f == 0.0:
21 continue
22 phit_r = np.array([phit(r) for r in rgd.r_g])
23 G_k, phit_k = rgd.fft(phit_r * rgd.r_g**(l + 1), l)
24 e_k += f * 0.5 * phit_k**2 * G_k**4 / (2 * pi)**3
25 e0 -= f * de
27 return G_k, e_k, e0
30def dekindecut(G: Array1D, de: Array1D, ecut: float) -> float:
31 """Linear interpolation."""
32 dG = G[1]
33 G0 = (2 * ecut)**0.5
34 g = int(G0 / dG)
35 dedG = np.polyval(np.polyfit(G[g:g + 2], de[g:g + 2], 1), G0)
36 dedecut = dedG / G0
37 return dedecut
40if __name__ == '__main__':
41 import argparse
42 import matplotlib.pyplot as plt
43 from gpaw.setup import create_setup
45 parser = argparse.ArgumentParser(
46 description='Calculate approximation to the energy variation with '
47 'plane-wave cutoff energy. The approximation is to use the kinetic '
48 'energy from a PAW atom, which can be calculated efficiently on '
49 'a radial grid.')
50 parser.add_argument('-d', '--derivative', type=float, metavar='ECUT',
51 help='Calculate derivative of energy correction with '
52 'respect to plane-wave cutoff energy.')
53 parser.add_argument('name', help='Name of PAW dataset.')
54 args = parser.parse_args()
56 ds = create_setup(args.name)
58 G, de, e0 = ekin(ds)
59 dG = G[1]
61 if args.derivative:
62 dedecut = -dekindecut(G, de, args.derivative / Ha)
63 print('de/decut({}, {} eV) = {:.6f}'
64 .format(args.name, args.derivative, dedecut))
65 else:
66 de = (np.add.accumulate(de) - 0.5 * de[0] - 0.5 * de) * dG
68 ecut = 0.5 * G**2 * Ha
69 y = (de[-1] - de) * Ha
70 ax = plt.figure().add_subplot(111)
71 ax.plot(ecut, y)
72 ax.set_xlim(300.0, 1000.0)
73 ax.set_ylim(0.0, y[ecut > 300.0][0])
74 plt.show()