Coverage for gpaw/gauss.py: 79%

85 statements  

« prev     ^ index     » next       coverage.py v7.7.1, created at 2025-07-08 00:17 +0000

1# Copyright (C) 2003 CAMP 

2# Please see the accompanying LICENSE file for further information. 

3 

4import numpy as np 

5from scipy.special import erf 

6 

7 

8def I(R, a, b, alpha, beta): # noqa 

9 """Calculate integral and derivatives wrt. positions of Gaussian product. 

10 

11 :: 

12 

13 / 2 2 

14 | a0+b0 a1+b1 a2+b2 -alpha r -beta (r-R) 

15 value = | x y z e e dr, 

16 | 

17 / 

18 

19 Returns the tuple (value, d[value]/dx, d[value]/dy, d[value]/dz). 

20 """ 

21 result = np.zeros(4) 

22 R = np.array(R) 

23 result[0] = I1(R, a, b, alpha, beta) 

24 a = np.array(a) 

25 for i in range(3): 

26 a[i] += 1 

27 result[1 + i] = 2 * alpha * I1(R, tuple(a), b, alpha, beta) 

28 a[i] -= 2 

29 if a[i] >= 0: 

30 result[1 + i] -= (a[i] + 1) * I1(R, tuple(a), b, alpha, beta) 

31 a[i] += 1 

32 return result 

33 

34 

35def I1(R, ap1, b, alpha, beta, m=0): 

36 if ap1 == (0, 0, 0): 

37 if b != (0, 0, 0): 

38 return I1(-R, b, ap1, beta, alpha, m) 

39 else: 

40 f = 2 * np.sqrt(np.pi**5 / (alpha + beta)) / (alpha * beta) 

41 if R.any(): 

42 T = alpha * beta / (alpha + beta) * np.dot(R, R) 

43 f1 = f * erf(T**0.5) * (np.pi / T)**0.5 

44 if m == 0: 

45 return 0.5 * f1 

46 f2 = f * np.exp(-T) / T**m 

47 if m == 1: 

48 return 0.25 * f1 / T - 0.5 * f2 

49 if m == 2: 

50 return 0.375 * f1 / T**2 - 0.5 * f2 * (1.5 + T) 

51 if m == 3: 

52 return 0.9375 * f1 / T**3 - 0.25 * f2 * (7.5 + 

53 T * (5 + 2 * T)) 

54 if m == 4: 

55 return 3.28125 * f1 / T**4 - 0.125 * f2 * \ 

56 (52.5 + T * (35 + 2 * T * (7 + 2 * T))) 

57 if m == 5: 

58 return 14.7656 * f1 / T**5 - 0.03125 * f2 * \ 

59 (945 + T * (630 + T * (252 + T * (72 + T * 16)))) 

60 if m == 6: 

61 return 81.2109 * f1 / T**6 - 0.015625 * f2 * \ 

62 (10395 + T * 

63 (6930 + T * 

64 (2772 + T * (792 + T * (176 + T * 32))))) 

65 else: 

66 raise NotImplementedError 

67 

68 return f / (1 + 2 * m) 

69 for i in range(3): 

70 if ap1[i] > 0: 

71 break 

72 a = ap1[:i] + (ap1[i] - 1,) + ap1[i + 1:] 

73 result = beta / (alpha + beta) * R[i] * I1(R, a, b, alpha, beta, m + 1) 

74 if a[i] > 0: 

75 am1 = a[:i] + (a[i] - 1,) + a[i + 1:] 

76 result += a[i] / (2 * alpha) * (I1(R, am1, b, alpha, beta, m) - 

77 beta / (alpha + beta) * 

78 I1(R, am1, b, alpha, beta, m + 1)) 

79 if b[i] > 0: 

80 bm1 = b[:i] + (b[i] - 1,) + b[i + 1:] 

81 result += b[i] / (2 * (alpha + beta)) * I1(R, 

82 a, bm1, alpha, beta, m + 1) 

83 return result 

84 

85 

86def test_derivatives(R, a, b, alpha, beta, i): 

87 R = np.array(R) 

88 a = np.array(a) 

89 a[i] += 1 

90 dIdRi = 2 * alpha * I1(R, tuple(a), b, alpha, beta) 

91 a[i] -= 2 

92 if a[i] >= 0: 

93 dIdRi -= (a[i] + 1) * I1(R, tuple(a), b, alpha, beta) 

94 a[i] += 1 

95 dr = 0.001 

96 R[i] += 0.5 * dr 

97 dIdRi2 = I1(R, tuple(a), b, alpha, beta) 

98 R[i] -= dr 

99 dIdRi2 -= I1(R, tuple(a), b, alpha, beta) 

100 dIdRi2 /= -dr 

101 R[i] += 0.5 * dr 

102 return dIdRi, dIdRi2 

103 

104 

105class Gauss: 

106 """Normalised Gauss distribution 

107 

108 from gpaw.gauss import Gauss 

109 

110 width=0.4 

111 gs = Gauss(width) 

112 

113 for i in range(4): 

114 print('Gauss(i)=', gs.get(i)) 

115 """ 

116 def __init__(self, width=0.08): 

117 self.dtype = float 

118 self.set_width(width) 

119 

120 def get(self, x, x0=0): 

121 return self.norm * np.exp(-((x - x0) * self.wm1)**2) 

122 

123 def set_width(self, width=0.08): 

124 self.norm = 1. / width / np.sqrt(2 * np.pi) 

125 self.wm1 = np.sqrt(.5) / width 

126 self._fwhm = np.sqrt(8 * np.log(2)) * width 

127 

128 @property 

129 def fwhm(self): 

130 return self._fwhm 

131 

132 @fwhm.setter 

133 def fwhm(self, value): 

134 self.set_width(value / np.sqrt(8 * np.log(2)))