Coverage for gpaw/response/site_paw.py: 100%
39 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
1import numpy as np
3from gpaw.gaunt import gaunt
4from gpaw.sphere.rshe import RealSphericalHarmonicsExpansion
5from gpaw.sphere.integrate import radial_truncation_function
8def calculate_site_matrix_element_correction(
9 pawdata, rshe: RealSphericalHarmonicsExpansion,
10 rcut_p, drcut, lambd_p):
11 r"""Calculate the PAW correction to a site matrix element.
13 For the site matrix element
15 f^ap_nn' = <ψ_n|Θ(r∊Ω_ap)f(r)|ψ_n'>
17 the PAW correction for each pair of partial waves i and i' is given by
18 l
19 __ __
20 ap \ \ m,mi,mi' / a a ̰ a ̰ a
21 F = / / g | r^2 dr θ(r<rc) f (r) [φ(r) φ(r) - φ(r) φ(r)]
22 ii' ‾‾ ‾‾ l,li,li' / p lm i i' i i'
23 l m=-l
25 where g refer to the Gaunt coefficients and f_lm(r) are the real
26 spherical harmonics expansion coefficients of the function f(r).
28 Here, we evaluate the correction F_ii'^ap for various smooth truncation
29 functions θ_p(r<rc), parametrized by rc, Δrc and λ.
30 """
31 rgd = rshe.rgd
32 assert rgd is pawdata.xc_correction.rgd
33 ni = pawdata.ni # Number of partial waves
34 l_j = pawdata.l_j # l-index for each radial function index j
35 lmax = max(l_j)
36 G_LLL = gaunt(lmax)
37 assert max(rshe.l_M) <= lmax * 2
38 # (Real) radial functions for the partial waves
39 phi_jg = pawdata.phi_jg
40 phit_jg = pawdata.phit_jg
41 # Truncate the radial functions to span only the radial grid coordinates
42 # which need correction
43 assert np.allclose(rgd.r_g - pawdata.rgd.r_g[:rgd.N], 0.)
44 phi_jg = np.array(phi_jg)[:, :rgd.N]
45 phit_jg = np.array(phit_jg)[:, :rgd.N]
47 # Calculate smooth truncation functions and allocate array
48 Np = len(rcut_p)
49 assert len(lambd_p) == Np
50 theta_pg = [radial_truncation_function(rgd.r_g, rcut, drcut, lambd)
51 for rcut, lambd in zip(rcut_p, lambd_p)]
52 F_pii = np.zeros((Np, ni, ni), dtype=float)
54 # Loop of radial function indices for partial waves i and i'
55 i1_counter = 0
56 for j1, l1 in enumerate(l_j):
57 i2_counter = 0
58 for j2, l2 in enumerate(l_j):
59 # Calculate the radial partial wave correction
60 dn_g = phi_jg[j1] * phi_jg[j2] - phit_jg[j1] * phit_jg[j2]
62 # Generate m-indices for each radial function
63 for m1 in range(2 * l1 + 1):
64 for m2 in range(2 * l2 + 1):
65 # Set up the i=(l,m) index for each partial wave
66 i1 = i1_counter + m1
67 i2 = i2_counter + m2
69 # Loop through the real spherical harmonics of the local
70 # function f(r)
71 for L, f_g in zip(rshe.L_M, rshe.f_gM.T):
72 # Angular integral
73 gaunt_coeff = G_LLL[l1**2 + m1, l2**2 + m2, L]
74 if gaunt_coeff == 0:
75 continue
76 # Radial integral
77 for p, theta_g in enumerate(theta_pg):
78 F_pii[p, i1, i2] += \
79 gaunt_coeff * rgd.integrate_trapz(
80 theta_g * f_g * dn_g)
82 # Add to i and i' counters
83 i2_counter += 2 * l2 + 1
84 i1_counter += 2 * l1 + 1
85 return F_pii