Coverage for gpaw/pw/density.py: 96%
80 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
1from math import pi
2import numpy as np
4from gpaw.density import Density
5from gpaw.pw.descriptor import PWDescriptor, PWMapping
6from gpaw.pw.lfc import PWLFC
9class PseudoCoreKineticEnergyDensityLFC(PWLFC):
10 def add(self, tauct_R):
11 tauct_R += self.pd.ifft(1.0 / self.pd.gd.dv *
12 self.expand().sum(1).view(complex))
14 def derivative(self, dedtaut_R, dF_aiv):
15 PWLFC.derivative(self, self.pd.fft(dedtaut_R), dF_aiv)
18class ReciprocalSpaceDensity(Density):
19 def __init__(self, ecut,
20 gd, finegd, nspins, collinear, charge, redistributor,
21 background_charge=None):
22 Density.__init__(self, gd, finegd, nspins, collinear, charge,
23 redistributor=redistributor,
24 background_charge=background_charge)
25 ecut0 = 0.5 * pi**2 / (gd.h_cv**2).sum(1).max()
26 ecut = min(ecut, ecut0)
27 self.pd2 = PWDescriptor(ecut, gd)
28 self.pd3 = PWDescriptor(4 * ecut, finegd)
30 self.map23 = PWMapping(self.pd2, self.pd3)
32 self.nct_q = None
33 self.nt_Q = None
34 self.rhot_q = None
36 def initialize(self, setups, timer, magmom_av, hund):
37 Density.initialize(self, setups, timer, magmom_av, hund)
39 spline_aj = []
40 for setup in setups:
41 if setup.nct is None:
42 spline_aj.append([])
43 else:
44 spline_aj.append([setup.nct])
45 self.nct = PWLFC(spline_aj, self.pd2)
47 self.ghat = PWLFC([setup.ghat_l for setup in setups], self.pd3,
48 ) # blocksize=256, comm=self.xc_redistributor.comm)
50 def set_positions(self, spos_ac, atom_partition):
51 Density.set_positions(self, spos_ac, atom_partition)
52 self.nct_q = self.pd2.zeros()
53 self.nct.add(self.nct_q, 1.0 / self.nspins)
54 self.nct_G = self.pd2.ifft(self.nct_q)
56 def interpolate_pseudo_density(self, comp_charge=None):
57 """Interpolate pseudo density to fine grid."""
58 if comp_charge is None:
59 comp_charge, _Q_aL = self.calculate_multipole_moments()
61 if self.nt_xg is None:
62 self.nt_xg = self.finegd.empty(self.ncomponents)
63 self.nt_sg = self.nt_xg[:self.nspins]
64 self.nt_vg = self.nt_xg[self.nspins:]
65 self.nt_Q = self.pd2.empty()
67 self.nt_Q[:] = 0.0
69 x = 0
70 for nt_G, nt_g in zip(self.nt_xG, self.nt_xg):
71 nt_g[:], nt_Q = self.pd2.interpolate(nt_G, self.pd3)
72 if x < self.nspins:
73 self.nt_Q += nt_Q
74 x += 1
76 def interpolate(self, in_xR, out_xR=None):
77 """Interpolate array(s)."""
78 if out_xR is None:
79 out_xR = self.finegd.empty(in_xR.shape[:-3])
81 a_xR = in_xR.reshape((-1,) + in_xR.shape[-3:])
82 b_xR = out_xR.reshape((-1,) + out_xR.shape[-3:])
84 for in_R, out_R in zip(a_xR, b_xR):
85 out_R[:] = self.pd2.interpolate(in_R, self.pd3)[0]
87 return out_xR
89 distribute_and_interpolate = interpolate
91 def calculate_pseudo_charge(self):
92 self.rhot_q = self.pd3.zeros()
93 Q_aL = self.Q.calculate(self.D_asp)
94 self.ghat.add(self.rhot_q, Q_aL)
95 self.map23.add_to2(self.rhot_q, self.nt_Q)
96 self.background_charge.add_fourier_space_charge_to(self.pd3,
97 self.rhot_q)
99 def get_pseudo_core_kinetic_energy_density_lfc(self):
100 return PseudoCoreKineticEnergyDensityLFC(
101 [[setup.tauct] for setup in self.setups], self.pd2)
103 def calculate_dipole_moment(self):
104 pd = self.pd3
105 N_c = pd.tmp_Q.shape
107 m0_q, m1_q, m2_q = (i_G == 0
108 for i_G in np.unravel_index(pd.Q_qG[0], N_c))
109 rhot_q = self.pd3.gather(self.rhot_q)
110 if pd.comm.rank == 0:
111 irhot_q = rhot_q.imag
112 rhot_cs = [irhot_q[m1_q & m2_q],
113 irhot_q[m0_q & m2_q],
114 irhot_q[m0_q & m1_q]]
115 d_c = [np.dot(rhot_s[1:], 1.0 / np.arange(1, len(rhot_s)))
116 for rhot_s in rhot_cs]
117 d_v = -np.dot(d_c, pd.gd.cell_cv) / pi * pd.gd.dv
118 else:
119 d_v = np.empty(3)
120 pd.comm.broadcast(d_v, 0)
121 return d_v