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

1import numpy as np 

2from gpaw.solvation.gridmem import NeedsGD 

3 

4 

5class Dielectric(NeedsGD): 

6 """Class representing a spatially varying permittivity. 

7 

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 """ 

17 

18 def __init__(self, epsinf): 

19 """Constructor for the Dielectric class. 

20 

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 

30 

31 def todict(self): 

32 return {'epsinf': self.epsinf} 

33 

34 @classmethod 

35 def from_dict(self, dct): 

36 if not isinstance(dct, dict): 

37 return dct 

38 return LinearDielectric(**dct) 

39 

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) 

45 

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() 

54 

55 @property 

56 def epsinf(self): 

57 return self._epsinf 

58 

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) 

66 

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 ) 

77 

78 def update_eps_only(self): 

79 raise NotImplementedError 

80 

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 

86 

87 def write(self, writer): 

88 writer.write(name=self.__class__.__name__, epsinf=self._epsinf) 

89 

90 

91class LinearDielectric(Dielectric): 

92 """Dielectric depending (affine) linearly on the cavity. 

93 

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 

101 

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. 

105 

106 def write(self, writer): 

107 writer.write(name='LinearDielectric', 

108 epsinf=self.epsinf) 

109 

110 

111class CMDielectric(Dielectric): 

112 """Clausius-Mossotti like dielectric. 

113 

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 )