Coverage for gpaw/solvation/dielectric.py: 85%
68 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 numpy as np
2from gpaw.solvation.gridmem import NeedsGD
5class Dielectric(NeedsGD):
6 """Class representing a spatially varying permittivity.
8 Attributes:
9 eps_gradeps -- List [eps_g, dxeps_g, dyeps_g, dzeps_g]
10 with
11 eps_g: permittivity on the fine grid
12 dieps_g: gradient of eps_g.
13 del_eps_del_g_g -- Partial derivative with respect to
14 the cavity. (A point-wise dependence
15 on the cavity is assumed).
16 """
18 def __init__(self, epsinf):
19 """Constructor for the Dielectric class.
21 Arguments:
22 epsinf -- Static dielectric constant
23 at infinite distance from the solute.
24 """
25 NeedsGD.__init__(self)
26 self._epsinf = float(epsinf)
27 self.eps_gradeps = None # eps_g, dxeps_g, dyeps_g, dzeps_g
28 self.del_eps_del_g_g = None
29 self.cavity = None
31 def todict(self):
32 return {'epsinf': self.epsinf}
34 @classmethod
35 def from_dict(self, dct):
36 if not isinstance(dct, dict):
37 return dct
38 return LinearDielectric(**dct)
40 def estimate_memory(self, mem):
41 nbytes = self.gd.bytecount()
42 mem.subnode('Permittivity', nbytes)
43 mem.subnode('Permittivity Gradient', 3 * nbytes)
44 mem.subnode('Permittivity Derivative', nbytes)
46 def allocate(self):
47 NeedsGD.allocate(self)
48 self.eps_gradeps = []
49 eps_g = self.gd.empty()
50 eps_g.fill(1.0)
51 self.eps_gradeps.append(eps_g)
52 self.eps_gradeps.extend([gd.zeros() for gd in (self.gd, ) * 3])
53 self.del_eps_del_g_g = self.gd.empty()
55 @property
56 def epsinf(self):
57 return self._epsinf
59 @epsinf.setter
60 def epsinf(self, epsinf):
61 if epsinf != self._epsinf:
62 self._epsinf = float(epsinf)
63 self.del_eps_del_g_g = self._epsinf - 1.
64 if self.cavity is not None:
65 self.update(self.cavity)
67 def update(self, cavity):
68 """Calculate eps_gradeps and del_eps_del_g_g from the cavity."""
69 self.cavity = cavity
70 self.update_eps_only()
71 for i in (0, 1, 2):
72 np.multiply(
73 self.del_eps_del_g_g,
74 cavity.grad_g_vg[i],
75 self.eps_gradeps[1 + i]
76 )
78 def update_eps_only(self):
79 raise NotImplementedError
81 def __str__(self):
82 s = 'Dielectric:\n'
83 s += f' Type: {self.__class__.__name__}\n'
84 s += f' Solvent dielectric constant: {self._epsinf}'
85 return s
87 def write(self, writer):
88 writer.write(name=self.__class__.__name__, epsinf=self._epsinf)
91class LinearDielectric(Dielectric):
92 """Dielectric depending (affine) linearly on the cavity.
94 See also
95 A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014).
96 """
97# name='LinearDielectric'
98 def allocate(self):
99 Dielectric.allocate(self)
100 self.del_eps_del_g_g = self._epsinf - 1. # frees array
102 def update_eps_only(self):
103 np.multiply(self.cavity.g_g, self._epsinf - 1., self.eps_gradeps[0])
104 self.eps_gradeps[0] += 1.
106 def write(self, writer):
107 writer.write(name='LinearDielectric',
108 epsinf=self.epsinf)
111class CMDielectric(Dielectric):
112 """Clausius-Mossotti like dielectric.
114 Untested, use at own risk!
115 """
116# name='Clausius-Mossotti like dielectric'
117 def update_eps_only(self):
118 ei = self._epsinf
119 t = 1. - self.cavity.g_g
120 self.eps_gradeps[0][:] = (3. * (ei + 2.)) / ((ei - 1.) * t + 3.) - 2.
121 self.del_eps_del_g_g[:] = (
122 (3. * (ei - 1.) * (ei + 2.)) / ((ei - 1.) * t + 3.) ** 2
123 )