Coverage for gpaw/jellium.py: 81%
47 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
1"""Helper classes for doing jellium calculations."""
2from math import pi
4import numpy as np
5from ase.units import Bohr
6from gpaw.new.environment import Jellium as JelliumEnv
9def create_background_charge(**kwargs):
10 if 'z1' in kwargs:
11 return JelliumSlab(**kwargs)
12 return Jellium(**kwargs)
15class Jellium():
16 """ The Jellium object """
17 def __init__(self, charge):
18 """ Initialize the Jellium object
20 Input: charge, the total Jellium background charge.
21 """
22 self.charge = charge
23 self.rs = None # the Wigner-Seitz radius
24 self.volume = None
25 self.mask_g = None
26 self.gd = None
28 def todict(self):
29 return {'charge': self.charge}
31 def set_grid_descriptor(self, gd):
32 """ Set the grid descriptor for the Jellium background charge"""
33 self.gd = gd
34 self.mask_g = self.get_mask().astype(float)
35 self.volume = self.gd.comm.sum_scalar(self.mask_g.sum()) * self.gd.dv
36 if self.charge != 0.:
37 self.rs = (3 / pi / 4 * self.volume / abs(self.charge))**(1 / 3)
38 else:
39 self.rs = np.inf # Avoid having to see numpy's warning.
41 def get_mask(self):
42 """Choose which grid points are inside the jellium.
44 gd: grid descriptor
46 Return ndarray of ones and zeros indicating where the jellium
47 is. This implementation will put the positive background in the
48 whole cell. Overwrite this method in subclasses."""
50 return self.gd.zeros() + 1.0
52 def add_charge_to(self, rhot_g):
53 """ Add Jellium background charge to pseudo charge density rhot_g"""
54 rhot_g -= self.mask_g * (self.charge / self.volume)
56 def add_fourier_space_charge_to(self, pd, rhot_q):
57 rhot_g = pd.gd.zeros()
58 self.add_charge_to(rhot_g)
59 rhot_q += pd.fft(rhot_g)
61 def build(self,
62 setups,
63 grid,
64 relpos_ac,
65 log,
66 comm,
67 **kwargs) -> JelliumEnv:
68 self.set_grid_descriptor(grid._gd)
69 return JelliumEnv(self, len(relpos_ac), grid)
72class JelliumSlab(Jellium):
73 """ The Jellium slab object """
74 def __init__(self, charge, z1, z2):
75 """Put the positive background charge where z1 < z < z2.
77 z1: float
78 Position of lower surface in Angstrom units.
79 z2: float
80 Position of upper surface in Angstrom units."""
81 Jellium.__init__(self, charge)
82 self.z1 = (z1 - 0.0001) / Bohr
83 self.z2 = (z2 - 0.0001) / Bohr
85 def todict(self):
86 dct = Jellium.todict(self)
87 dct.update(z1=self.z1 * Bohr + 0.0001,
88 z2=self.z2 * Bohr + 0.0001)
89 return dct
91 def get_mask(self):
92 r_gv = self.gd.get_grid_point_coordinates().transpose((1, 2, 3, 0))
93 # r_gv: 4-dimensional ndarray
94 # positions of the grid points in Bohr units.
95 return np.logical_and(r_gv[:, :, :, 2] > self.z1,
96 r_gv[:, :, :, 2] < self.z2)