Coverage for gpaw/elf.py: 86%
44 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
1"""This module defines an ELF function."""
2from __future__ import annotations
4import sys
6import numpy as np
7from gpaw.core import UGArray
8from gpaw.fd_operators import Gradient
9from gpaw.new.ase_interface import GPAW, ASECalculator
10from gpaw.new.calculation import DFTCalculation
13def elf(nt_sR: np.ndarray,
14 nt_grad2_sR: np.ndarray,
15 taut_sR: np.ndarray,
16 ncut: float | None = None) -> np.ndarray:
17 """Pseudo electron localisation function (ELF).
19 See:
21 Becke and Edgecombe, J. Chem. Phys., vol 92 (1990) 5397
23 More comprehensive definition in
24 M. Kohout and A. Savin, Int. J. Quantum Chem., vol 60 (1996) 875-882
26 Parameters
27 ==========
28 nt_sR:
29 Pseudo valence density.
30 nt_grad2_sR:
31 Squared norm of the density gradient.
32 taut_sR:
33 Kinetic energy density.
34 ncut:
35 Minimum density cutoff parameter.
37 Returns
38 =======
39 np.ndarray:
40 Array of ELF values.
41 """
43 # Fermi constant
44 cF = 3.0 / 10 * (3 * np.pi**2)**(2 / 3)
46 eps = 1e-11
47 nt_sR = nt_sR.copy()
48 nt_sR[nt_sR < eps] = eps
50 if nt_sR.shape[0] == 2:
51 # Kouhut eq. (9)
52 D0 = 2**(2 / 3) * cF * (nt_sR[0]**(5 / 3) +
53 nt_sR[1]**(5 / 3))
55 taut = taut_sR.sum(axis=0)
56 D = taut - (nt_grad2_sR[0] / nt_sR[0] + nt_grad2_sR[1] / nt_sR[1]) / 8
57 else:
58 # Kouhut eq. (7)
59 D0 = cF * nt_sR[0]**(5 / 3)
60 taut = taut_sR[0]
61 D = taut - nt_grad2_sR[0] / nt_sR[0] / 8
63 elf_R = 1.0 / (1.0 + (D / D0)**2)
65 if ncut is not None:
66 nt = nt_sR.sum(axis=0)
67 elf_R[nt < ncut] = 0.0
69 return elf_R
72def elf_from_dft_calculation(dft: DFTCalculation | ASECalculator,
73 ncut: float = 1e-6) -> UGArray:
74 """Calculate the electronic localization function.
76 Parameters
77 ==========
78 dft:
79 DFT-calculation object.
80 ncut:
81 Density cutoff below which the ELF is zero.
83 Returns
84 =======
85 UGArray:
86 ELF values.
87 """
88 if isinstance(dft, ASECalculator):
89 dft = dft.dft
90 density = dft.density
91 density.update_ked(dft.ibzwfs)
92 taut_sR = density.taut_sR
93 assert taut_sR is not None
94 nt_sR = density.nt_sR
95 grad_v = [Gradient(nt_sR.desc._gd, v, n=2) for v in range(3)]
96 gradnt2_sR = nt_sR.new(zeroed=True)
97 for gradnt2_R, nt_R in zip(gradnt2_sR, nt_sR):
98 for grad in grad_v:
99 gradnt_R = grad(nt_R)
100 gradnt2_R.data += gradnt_R.data**2
101 elf_R = nt_sR.desc.empty()
102 elf_R.data[:] = elf(
103 nt_sR.data, gradnt2_sR.data, taut_sR.data, ncut)
104 return elf_R
107if __name__ == '__main__':
108 e_R = elf_from_dft_calculation(GPAW(sys.argv[1]).dft, 0.001)
109 e_R.isosurface(isomin=0.8, isomax=0.8)