Coverage for gpaw/response/g0w0_kernels.py: 97%
38 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
1from ase.units import Ha
2import numpy as np
3from gpaw.xc.fxc import KernelWave, XCFlags, FXCCache
4from gpaw.xc.rpa import GCut
6from gpaw.response.qpd import SingleQPWDescriptor
7from gpaw.pw.descriptor import PWMapping
10class G0W0Kernel:
11 def __init__(self, xc, context, **kwargs):
12 self.xc = xc
13 self.context = context
14 self.xcflags = XCFlags(xc)
15 self._kwargs = kwargs
17 def calculate(self, qpd):
18 if self.xc == 'RPA':
19 return np.eye(qpd.ngmax)
21 return calculate_spinkernel(
22 qpd=qpd,
23 xcflags=self.xcflags,
24 context=self.context,
25 **self._kwargs)
28def calculate_spinkernel(*, ecut, xcflags, gs, qd, qpd, context):
29 assert xcflags.spin_kernel
30 xc = xcflags.xc
31 ns = gs.nspins
32 ibzq_qc = qd.ibzk_kc
33 iq = np.argmin(np.linalg.norm(ibzq_qc - qpd.q_c[np.newaxis], axis=1))
34 assert np.allclose(ibzq_qc[iq], qpd.q_c)
36 ecut_max = ecut * Ha # XXX very ugly this
38 cache = FXCCache(comm=context.comm,
39 tag=gs.atoms.get_chemical_formula(mode='hill'),
40 xc=xc, ecut=ecut_max)
41 handle = cache.handle(iq)
43 if not handle.exists():
44 # Somehow we calculated many q even though this function
45 # only works on one q? Very confusing.
46 kernel = KernelWave(
47 q_empty=iq, ibzq_qc=qd.ibzk_kc,
48 xc=xcflags.xc,
49 ecut=ecut_max, gs=gs,
50 context=context)
52 # The first time we miss the cache, we calculate /all/ iq.
53 # (Whether that's the best strategy can be discussed.)
54 for iq_calculated, array in kernel.calculate_fhxc():
55 cache.handle(iq_calculated).write(array)
57 fv = handle.read()
58 assert fv is not None
60 # If we want a reduced plane-wave description, create qpd mapping
61 if qpd.ecut < ecut:
62 # Recreate nonreduced plane-wave description corresponding to ecut_max
63 qpdnr = SingleQPWDescriptor.from_q(qpd.q_c, ecut, qpd.gd,
64 gammacentered=qpd.gammacentered)
65 pw_map = PWMapping(qpd, qpdnr)
66 gcut = GCut(pw_map.G2_G1)
67 fv = gcut.spin_cut(fv, ns=ns)
69 return fv