-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathOperators.py
167 lines (131 loc) · 4.39 KB
/
Operators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import numpy as np
from vampyr import vampyr3d as vp
class HelmholtzOperator():
"""
Vectorized Helmholtz operator
Parameters
----------
mra : The multiresolution analysis we work on
lamb : vector of lambda parameters, mu_i = sqrt(-2*lambda_i)
prec : Precision requirement
Attributes
----------
operators : list containing HelmholtzOperators for each orbital
"""
def __init__(self, mra, lamb, prec):
self.mra = mra
self.lamb = lamb
self.prec = prec
self.operators = []
self.setup()
def setup(self):
mu = [np.sqrt(-2.0*l) if l < 0 else 1.0 for l in self.lamb]
for m in mu:
self.operators.append(vp.HelmholtzOperator(mra=self.mra, exp=m, prec=self.prec))
def __call__(self, Psi):
"""Operate the Helmholtz operator onto an orbital vector"""
return np.array([self.operators[i](Psi[i]) for i in range(len(Psi))])
class ExchangeOperator():
"""
Vectorized Exchange operator
K(phi) = \sum_i P[phi * psi_i] * psi_i
Parameters
----------
mra : The multiresolution analysis we work on
Psi : Orbital vector defining the operator
prec : Precision requirement
Attributes
----------
poisson : Poisson Operator
"""
def __init__(self, mra, Psi, prec):
self.mra = mra
self.Psi = Psi
self.prec = prec
self.poisson = vp.PoissonOperator(mra=mra, prec=self.prec)
def __call__(self, Phi):
"""Apply the exchange operator onto an orbital vector Phi"""
Phi_out = []
for j in range(len(Phi)):
V_j0 = self.poisson(Phi[j] * self.Psi[0])
tmp = (self.Psi[0] * V_j0).crop(self.prec)
for i in range(1, len(self.Psi)):
V_ji = self.poisson(Phi[j] * self.Psi[i])
tmp += (self.Psi[i] * V_ji).crop(self.prec)
tmp *= 4.0*np.pi
Phi_out.append(tmp)
return np.array([phi.crop(self.prec) for phi in Phi_out])
class CouloumbOperator():
"""
Vectorized Couloumb operator
J(phi) = \sum_i P[psi_i * psi_i] * phi
Parameters
----------
mra : The multiresolution analysis we work on
Psi : Orbital vector defining the operator
prec : Precision requirement
Attributes
----------
poisson : Poisson operator
potential : Coulomb potential
"""
def __init__(self, mra, Psi, prec):
self.mra = mra
self.Psi = Psi
self.prec = prec
self.poisson = vp.PoissonOperator(mra=mra, prec=self.prec)
self.potential = None
self.setup()
def setup(self):
rho = self.Psi[0]**2
for i in range(1, len(self.Psi)):
rho += self.Psi[i]**2
rho.crop(self.prec)
self.potential = (4.0*np.pi)*self.poisson(rho).crop(self.prec)
def __call__(self, Phi):
"""Apply Couloumb operator onto an orbital vector Phi"""
return np.array([(self.potential*phi).crop(self.prec) for phi in Phi])
class NuclearOperator():
"""
Vectorized Nuclear potential operator
Parameters
----------
mra : The multiresolution analysis we work on
atoms : List of dicts containing charge and coordinates of the atoms
prec : Precision requirement
Attributes
----------
potential : Nuclear potential
"""
def __init__(self, mra, atoms, prec):
self.mra = mra
self.prec= prec
self.atoms = atoms
self.potential = None
self.setup()
def setup(self):
# Project analytic function onto MRA basis
P_mra = vp.ScalingProjector(mra=self.mra, prec=self.prec)
f_nuc = NuclearFunction(self.atoms)
self.potential = P_mra(f_nuc)
def __call__(self, Phi):
"""Apply nuclear potential operator onto an orbital vector"""
return np.array([(self.potential*phi).crop(self.prec) for phi in Phi])
class NuclearFunction():
"""
Vectorized Nuclear potential operator
Parameters
----------
atoms : List of dicts containing charge and coordinates of the atoms
"""
def __init__(self, atoms):
self.atoms = atoms
def __call__(self, r):
"Returns the nuclear potential value in R"
tmp = 0.0
for atom in self.atoms:
Z = atom["Z"]
R = atom["R"]
R2 = (R[0]-r[0])**2 + (R[1]-r[1])**2 + (R[2]-r[2])**2
tmp += -Z / np.sqrt(R2)
return tmp