Coverage for gpaw/preconditioner.py: 95%
74 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
1import gpaw.cgpaw as cgpaw
2import numpy as np
4from gpaw import debug
5from gpaw.fd_operators import Laplace
6from gpaw.transformers import Transformer
9class Preconditioner:
10 def __init__(self, gd0, kin0, dtype=float, block=1, xp=np):
11 gd1 = gd0.coarsen()
12 gd2 = gd1.coarsen()
13 self.kin0 = kin0
14 self.kin1 = Laplace(gd1, -0.5, 1, dtype, xp=xp)
15 self.kin2 = Laplace(gd2, -0.5, 1, dtype, xp=xp)
16 self.scratch0 = gd0.zeros((2, block), dtype, False, xp=xp)
17 self.scratch1 = gd1.zeros((3, block), dtype, False, xp=xp)
18 self.scratch2 = gd2.zeros((3, block), dtype, False, xp=xp)
19 self.step = 0.66666666 / kin0.get_diagonal_element()
21 self.restrictor_object0 = Transformer(gd0, gd1, 1, dtype, xp=xp)
22 self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype, xp=xp)
23 self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype, xp=xp)
24 self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype, xp=xp)
25 self.restrictor0 = self.restrictor_object0.apply
26 self.restrictor1 = self.restrictor_object1.apply
27 self.interpolator2 = self.interpolator_object2.apply
28 self.interpolator1 = self.interpolator_object1.apply
29 self.use_c_precond = True
30 self.xp = xp
32 def calculate_kinetic_energy(self, psit_xG, kpt):
33 return None
35 def __call__(self, residuals, kpt, ekin=None, out=None):
36 if residuals.ndim == 3:
37 if out is None:
38 return self.__call__(residuals[np.newaxis], kpt)[0]
39 return self.__call__(residuals[np.newaxis], kpt,
40 out=out[np.newaxis])[0]
42 nb = len(residuals) # number of bands
43 nb0 = self.scratch0.shape[1]
44 if nb > nb0:
45 assert out is not None
46 for n1 in range(0, nb, nb0):
47 self(residuals[n1:n1 + nb0], kpt, out=out[n1:n1 + nb0])
48 return out
50 phases = kpt.phase_cd
51 step = self.step
52 if out is None:
53 d0, q0 = self.scratch0[:, :nb]
54 else:
55 d0 = out
56 q0 = self.scratch0[0, :nb]
57 r1, d1, q1 = self.scratch1[:, :nb]
58 r2, d2, q2 = self.scratch2[:, :nb]
59 if self.use_c_precond and self.xp is np:
60 transformers = [self.restrictor_object0.transformer,
61 self.restrictor_object1.transformer,
62 self.interpolator_object1.transformer,
63 self.interpolator_object2.transformer]
64 if debug:
65 # Unwrap wrapper:
66 transformers = [getattr(t, 'transformer', t)
67 for t in transformers]
68 cgpaw.fd_precond(*transformers,
69 self.kin0.operator, self.kin1.operator,
70 self.kin2.operator,
71 d0, q0, r1, d1, q1, r2, d2, q2,
72 residuals, -residuals, step, phases)
73 return d0
74 self.restrictor0(-residuals, r1, phases)
75 d1[:] = 4 * step * r1
76 self.kin1.apply(d1, q1, phases)
77 q1 -= r1
78 self.restrictor1(q1, r2, phases)
79 d2 = 16 * step * r2
80 self.kin2.apply(d2, q2, phases)
81 q2 -= r2
82 d2 -= 16 * step * q2
83 self.interpolator2(d2, q1, phases)
84 d1 -= q1
85 self.kin1.apply(d1, q1, phases)
86 q1 -= r1
87 d1 -= 4 * step * q1
88 self.interpolator1(-d1, d0, phases)
89 self.kin0.apply(d0, q0, phases)
90 q0 -= residuals
91 d0 -= step * q0
92 d0 *= -1.0
93 return d0