root / ase / transport / tools.py @ 1
Historique | Voir | Annoter | Télécharger (14,08 ko)
1 |
import numpy as np |
---|---|
2 |
from math import sqrt, exp |
3 |
|
4 |
def tri2full(H_nn, UL='L'): |
5 |
"""Fill in values of hermitian matrix.
|
6 |
|
7 |
Fill values in lower or upper triangle of H_nn based on the opposite
|
8 |
triangle, such that the resulting matrix is symmetric/hermitian.
|
9 |
|
10 |
UL='U' will copy (conjugated) values from upper triangle into the
|
11 |
lower triangle.
|
12 |
|
13 |
UL='L' will copy (conjugated) values from lower triangle into the
|
14 |
upper triangle.
|
15 |
"""
|
16 |
N, tmp = H_nn.shape |
17 |
assert N == tmp, 'Matrix must be square' |
18 |
#assert np.isreal(H_nn.diagonal()).all(), 'Diagonal should be real'
|
19 |
if UL != 'L': |
20 |
H_nn = H_nn.T |
21 |
|
22 |
for n in range(N - 1): |
23 |
H_nn[n, n + 1:] = H_nn[n + 1:, n].conj() |
24 |
|
25 |
def dagger(matrix): |
26 |
return np.conj(matrix.T)
|
27 |
|
28 |
def rotate_matrix(h, u): |
29 |
return np.dot(u.T.conj(), np.dot(h, u))
|
30 |
|
31 |
def get_subspace(matrix, index): |
32 |
"""Get the subspace spanned by the basis function listed in index"""
|
33 |
assert matrix.ndim == 2 and matrix.shape[0] == matrix.shape[1] |
34 |
return matrix.take(index, 0).take(index, 1) |
35 |
|
36 |
permute_matrix = get_subspace |
37 |
|
38 |
def normalize(matrix, S=None): |
39 |
"""Normalize column vectors.
|
40 |
|
41 |
::
|
42 |
|
43 |
<matrix[:,i]| S |matrix[:,i]> = 1
|
44 |
|
45 |
"""
|
46 |
for col in matrix.T: |
47 |
if S is None: |
48 |
col /= np.linalg.norm(col) |
49 |
else:
|
50 |
col /= np.sqrt(np.dot(col.conj(), np.dot(S, col))) |
51 |
|
52 |
def subdiagonalize(h_ii, s_ii, index_j): |
53 |
nb = h_ii.shape[0]
|
54 |
nb_sub = len(index_j)
|
55 |
h_sub_jj = get_subspace(h_ii, index_j) |
56 |
s_sub_jj = get_subspace(s_ii, index_j) |
57 |
e_j, v_jj = np.linalg.eig(np.linalg.solve(s_sub_jj, h_sub_jj)) |
58 |
normalize(v_jj, s_sub_jj) # normalize: <v_j|s|v_j> = 1
|
59 |
permute_list = np.argsort(e_j.real) |
60 |
e_j = np.take(e_j, permute_list) |
61 |
v_jj = np.take(v_jj, permute_list, axis=1)
|
62 |
|
63 |
#setup transformation matrix
|
64 |
c_ii = np.identity(nb, complex)
|
65 |
for i in xrange(nb_sub): |
66 |
for j in xrange(nb_sub): |
67 |
c_ii[index_j[i], index_j[j]] = v_jj[i, j] |
68 |
|
69 |
h1_ii = rotate_matrix(h_ii, c_ii) |
70 |
s1_ii = rotate_matrix(s_ii, c_ii) |
71 |
|
72 |
return h1_ii, s1_ii, c_ii, e_j
|
73 |
|
74 |
def cutcoupling(h, s, index_n): |
75 |
for i in index_n: |
76 |
s[:, i] = 0.0
|
77 |
s[i, :] = 0.0
|
78 |
s[i, i] = 1.0
|
79 |
Ei = h[i, i] |
80 |
h[:, i] = 0.0
|
81 |
h[i, :] = 0.0
|
82 |
h[i, i] = Ei |
83 |
|
84 |
def fermidistribution(energy, kt): |
85 |
#fermi level is fixed to zero
|
86 |
return 1.0 / (1.0 + np.exp(energy / kt) ) |
87 |
|
88 |
def fliplr(a): |
89 |
length=len(a)
|
90 |
b = [0] * length
|
91 |
for i in range(length): |
92 |
b[i] = a[length - i - 1]
|
93 |
return b
|
94 |
|
95 |
def plot_path(energy): |
96 |
import pylab |
97 |
pylab.plot(np.real(energy), np.imag(energy), 'b--o')
|
98 |
pylab.show() |
99 |
|
100 |
|
101 |
def function_integral(function, calcutype): |
102 |
#return the integral of the 'function' on 'intrange'
|
103 |
#the function can be a value or a matrix, arg1,arg2 are the possible
|
104 |
#parameters of the function
|
105 |
|
106 |
intctrl = function.intctrl |
107 |
if calcutype == 'eqInt': |
108 |
intrange = intctrl.eqintpath |
109 |
tol = intctrl.eqinttol |
110 |
if hasattr(function.intctrl, 'eqpath_radius'): |
111 |
radius = function.intctrl.eqpath_radius |
112 |
else:
|
113 |
radius = -1
|
114 |
if hasattr(function.intctrl, 'eqpath_origin'): |
115 |
origin = function.intctrl.eqpath_origin |
116 |
else:
|
117 |
origin = 1000
|
118 |
elif calcutype == 'neInt': |
119 |
intrange = intctrl.neintpath |
120 |
tol = intctrl.neinttol |
121 |
radius = -1
|
122 |
origin = 1000
|
123 |
elif calcutype == 'locInt': |
124 |
intrange = intctrl.locintpath |
125 |
tol = intctrl.locinttol |
126 |
if hasattr(function.intctrl, 'locpath_radius'): |
127 |
radius = function.intctrl.locpath_radius |
128 |
else:
|
129 |
radius = -1
|
130 |
if hasattr(function.intctrl, 'locpath_origin'): |
131 |
origin = function.intctrl.locpath_origin |
132 |
else:
|
133 |
origin = 1000
|
134 |
trace = 0
|
135 |
a = 0.
|
136 |
b = 1.
|
137 |
|
138 |
#Initialize with 13 function evaluations.
|
139 |
c = (a + b) / 2
|
140 |
h = (b - a) / 2
|
141 |
realmin = 2e-17
|
142 |
|
143 |
s = [.942882415695480, sqrt(2.0/3), |
144 |
.641853342345781, 1/sqrt(5.0), .236383199662150] |
145 |
s1 = [0] * len(s) |
146 |
s2 = [0] * len(s) |
147 |
for i in range(len(s)): |
148 |
s1[i] = c - s[i] * h |
149 |
s2[i] = c + fliplr(s)[i] * h |
150 |
x0 = [a] + s1 + [c] + s2 + [b] |
151 |
|
152 |
s0 = [.0158271919734802, .094273840218850, .155071987336585, |
153 |
.188821573960182, .199773405226859, .224926465333340] |
154 |
w0 = s0 + [.242611071901408] + fliplr(s0)
|
155 |
w1 = [1, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 1] |
156 |
w2 = [77, 0, 432, 0, 625, 0, 672, 0, 625, 0, 432, 0, 77] |
157 |
for i in range(len(w1)): |
158 |
w1[i] = w1[i] / 6.0
|
159 |
w2[i] = w2[i] / 1470.0
|
160 |
|
161 |
dZ = [intrange[:len(intrange) - 1], intrange[1:]] |
162 |
hmin = [0] * len(dZ[1]) |
163 |
|
164 |
path_type = [] |
165 |
for i in range(len(intrange) - 1): |
166 |
rs = np.abs(dZ[0][i] - origin)
|
167 |
re = np.abs(dZ[1][i] - origin)
|
168 |
if abs(rs - radius) < 1.0e-8 and abs(re - radius) < 1.0e-8: |
169 |
path_type.append('half_circle')
|
170 |
else:
|
171 |
path_type.append('line')
|
172 |
|
173 |
for i in range(len(dZ[1])): |
174 |
if path_type[i] == 'half_circle': |
175 |
dZ[0][i] = 0 |
176 |
dZ[1][i] = np.pi
|
177 |
for i in range(len(dZ[1])): |
178 |
dZ[1][i] = dZ[1][i] - dZ[0][i] |
179 |
hmin[i] = realmin / 1024 * abs(dZ[1][i]) |
180 |
|
181 |
|
182 |
temp = np.array([[1] * 13, x0]).transpose() |
183 |
|
184 |
Zx = np.dot(temp, np.array(dZ)) |
185 |
|
186 |
Zxx = [] |
187 |
for i in range(len(intrange) - 1): |
188 |
for j in range(13): |
189 |
Zxx.append(Zx[j][i]) |
190 |
|
191 |
ns = 0
|
192 |
ne = 12
|
193 |
if path_type[0] == 'line': |
194 |
yns = function.calgfunc(Zxx[ns], calcutype) |
195 |
elif path_type[0] == 'half_circle': |
196 |
energy = origin + radius * np.exp((np.pi - Zxx[ns + i]) * 1.j)
|
197 |
yns = -1.j * radius * np.exp(-1.j* Zxx[ns +i])* function.calgfunc(energy, calcutype) |
198 |
fcnt = 0
|
199 |
|
200 |
|
201 |
for n in range(len(intrange)-1): |
202 |
# below evaluate the integral and adjust the tolerance
|
203 |
Q1pQ0 = yns * (w1[0] - w0[0]) |
204 |
Q2pQ0 = yns * (w2[0] - w0[0]) |
205 |
fcnt = fcnt + 12
|
206 |
for i in range(1,12): |
207 |
if path_type[n] == 'line': |
208 |
yne = function.calgfunc(Zxx[ns + i], calcutype) |
209 |
elif path_type[n] == 'half_circle': |
210 |
energy = origin + radius * np.exp((np.pi -Zxx[ns + i]) * 1.j)
|
211 |
yne = -1.j * radius * np.exp(-1.j * Zxx[ns + i])* function.calgfunc(energy, calcutype) |
212 |
Q1pQ0 += yne * (w1[i] - w0[i]) |
213 |
Q2pQ0 += yne * (w2[i] - w0[i]) |
214 |
|
215 |
# Increase the tolerance if refinement appears to be effective
|
216 |
r = np.abs(Q2pQ0) / (np.abs(Q1pQ0) + np.abs(realmin)) |
217 |
dim = np.product(r.shape) |
218 |
r = np.sum(r) / dim |
219 |
if r > 0 and r < 1: |
220 |
thistol = tol / r |
221 |
else:
|
222 |
thistol = tol |
223 |
if path_type[n] == 'line': |
224 |
yne = function.calgfunc(Zxx[ne], calcutype) |
225 |
elif path_type[n] == 'half_circle': |
226 |
energy = origin + radius * np.exp((np.pi -Zxx[ne]) * 1.j)
|
227 |
yne = -1.j * radius * np.exp(-1.j * Zxx[ne])* function.calgfunc(energy, calcutype) |
228 |
#Call the recursive core integrator
|
229 |
|
230 |
Qk, xpk, wpk, fcnt, warn = quadlstep(function, Zxx[ns], |
231 |
Zxx[ne], yns, yne, |
232 |
thistol, trace, fcnt, |
233 |
hmin[n], calcutype, path_type[n], |
234 |
origin, radius) |
235 |
if n == 0: |
236 |
Q = np.copy(Qk) |
237 |
Xp = xpk[:] |
238 |
Wp = wpk[:] |
239 |
else:
|
240 |
Q += Qk |
241 |
Xp = Xp[:-1] + xpk
|
242 |
Wp = Wp[:-1] + [Wp[-1] + wpk[0]] + wpk[1:] |
243 |
if warn == 1: |
244 |
print 'warning: Minimum step size reached,singularity possible' |
245 |
elif warn == 2: |
246 |
print 'warning: Maximum function count excced; singularity likely' |
247 |
elif warn == 3: |
248 |
print 'warning: Infinite or Not-a-Number function value encountered' |
249 |
else:
|
250 |
pass
|
251 |
|
252 |
ns += 13
|
253 |
ne += 13
|
254 |
yns = np.copy(yne) |
255 |
|
256 |
return Q,Xp,Wp,fcnt
|
257 |
|
258 |
def quadlstep(f, Za, Zb, fa, fb, tol, trace, fcnt, hmin, calcutype, |
259 |
path_type, origin, radius): |
260 |
#Gaussian-Lobatto and Kronrod method
|
261 |
#QUADLSTEP Recursive core routine for integral
|
262 |
#input parameters:
|
263 |
# f ---------- function, here we just use the module calgfunc
|
264 |
# to return the value, if wanna use it for
|
265 |
# another one, change it
|
266 |
# Za, Zb ---------- the start and end point of the integral
|
267 |
# fa, fb ---------- the function value on Za and Zb
|
268 |
# fcnt ---------- the number of the funtion recalled till now
|
269 |
#output parameters:
|
270 |
# Q ---------- integral
|
271 |
# Xp ---------- selected points
|
272 |
# Wp ---------- weight
|
273 |
# fcnt ---------- the number of the function recalled till now
|
274 |
|
275 |
maxfcnt = 10000
|
276 |
|
277 |
# Evaluate integrand five times in interior of subintrval [a,b]
|
278 |
Zh = (Zb - Za) / 2.0
|
279 |
if abs(Zh) < hmin: |
280 |
# Minimun step size reached; singularity possible
|
281 |
Q = Zh * (fa + fb) |
282 |
if path_type == 'line': |
283 |
Xp = [Za, Zb] |
284 |
elif path_type == 'half_circle': |
285 |
Xp = [origin + radius * np.exp((np.pi - Za) * 1.j),
|
286 |
origin + radius * np.exp((np.pi - Zb) * 1.j)]
|
287 |
Wp = [Zh, Zh] |
288 |
warn = 1
|
289 |
return Q, Xp, Wp, fcnt, warn
|
290 |
fcnt += 5
|
291 |
if fcnt > maxfcnt:
|
292 |
#Maximum function count exceed; singularity likely
|
293 |
Q = Zh * (fa + fb) |
294 |
if path_type == 'line': |
295 |
Xp = [Za, Zb] |
296 |
elif path_type == 'half_circle': |
297 |
Xp = [origin + radius * np.exp((np.pi - Za) * 1.j),
|
298 |
origin + radius * np.exp((np.pi - Zb) * 1.j)]
|
299 |
Wp = [Zh, Zh] |
300 |
warn = 2
|
301 |
return Q, Xp, Wp, fcnt, warn
|
302 |
x = [0.18350341907227, 0.55278640450004, 1.0, |
303 |
1.44721359549996, 1.81649658092773]; |
304 |
Zx = [0] * len(x) |
305 |
y = [0] * len(x) |
306 |
for i in range(len(x)): |
307 |
x[i] *= 0.5
|
308 |
Zx[i] = Za + (Zb - Za) * x[i] |
309 |
if path_type == 'line': |
310 |
y[i] = f.calgfunc(Zx[i], calcutype) |
311 |
elif path_type == 'half_circle': |
312 |
energy = origin + radius * np.exp((np.pi - Zx[i]) * 1.j)
|
313 |
y[i] = f.calgfunc(energy, calcutype) |
314 |
#Four point Lobatto quadrature
|
315 |
s1 = [1.0, 0.0, 5.0, 0.0, 5.0, 0.0, 1.0] |
316 |
s2 = [77.0, 432.0, 625.0, 672.0, 625.0, 432.0, 77.0] |
317 |
Wk = [0] * 7 |
318 |
Wp = [0] * 7 |
319 |
for i in range(7): |
320 |
Wk[i] = (Zh / 6.0) * s1[i]
|
321 |
Wp[i] = (Zh / 1470.0) * s2[i]
|
322 |
if path_type == 'line': |
323 |
Xp = [Za] + Zx + [Zb] |
324 |
elif path_type == 'half_circle': |
325 |
Xp = [Za] + Zx + [Zb] |
326 |
for i in range(7): |
327 |
factor = -1.j * radius * np.exp(1.j * (np.pi - Xp[i])) |
328 |
Wk[i] *= factor |
329 |
Wp[i] *= factor |
330 |
Xp[i] = origin + radius * np.exp((np.pi - Xp[i]) * 1.j)
|
331 |
Qk = fa * Wk[0] + fb * Wk[6] |
332 |
Q = fa * Wp[0] + fb * Wp[6] |
333 |
for i in range(1, 6): |
334 |
Qk += y[i-1] * Wk[i]
|
335 |
Q += y[i-1] * Wp[i]
|
336 |
if np.isinf(np.max(np.abs(Q))):
|
337 |
Q = Zh * (fa + fb) |
338 |
if path_type == 'line': |
339 |
Xp = [Za, Zb] |
340 |
elif path_type == 'half_circle': |
341 |
Xp = [origin + radius * np.exp((np.pi - Za) * 1.j),
|
342 |
origin + radius * np.exp((np.pi - Zb) * 1.j)]
|
343 |
Wp = [Zh, Zh] |
344 |
warn = 3
|
345 |
return Qk, Xp, Wp, fcnt, warn
|
346 |
else:
|
347 |
pass
|
348 |
if trace:
|
349 |
print fcnt, real(Za), imag(Za), abs(Zh) |
350 |
#Check accurancy of integral over this subinterval
|
351 |
XXk = [Xp[0], Xp[2], Xp[4], Xp[6]] |
352 |
WWk = [Wk[0], Wk[2], Wk[4], Wk[6]] |
353 |
YYk = [fa, y[1], y[3], fb] |
354 |
if np.max(np.abs(Qk - Q)) <= tol:
|
355 |
warn = 0
|
356 |
return Q, XXk, WWk, fcnt, warn
|
357 |
#Subdivide into six subintevals
|
358 |
else:
|
359 |
Q, Xk, Wk, fcnt, warn = quadlstep(f, Za, Zx[1], fa, YYk[1], |
360 |
tol, trace, fcnt, hmin, |
361 |
calcutype, path_type, |
362 |
origin, radius) |
363 |
|
364 |
Qk, xkk, wkk, fcnt, warnk = quadlstep(f, Zx[1],
|
365 |
Zx[3], YYk[1], YYk[2], tol, trace, fcnt, hmin, |
366 |
calcutype, path_type, |
367 |
origin, radius) |
368 |
Q += Qk |
369 |
Xk = Xk[:-1] + xkk
|
370 |
Wk = Wk[:-1] + [Wk[-1] + wkk[0]] + wkk[1:] |
371 |
warn = max(warn, warnk)
|
372 |
|
373 |
Qk, xkk, wkk, fcnt, warnk = quadlstep(f, Zx[3], Zb, YYk[2], fb, |
374 |
tol, trace, fcnt, hmin, |
375 |
calcutype, path_type, |
376 |
origin, radius) |
377 |
Q += Qk |
378 |
Xk = Xk[:-1] + xkk
|
379 |
Wk = Wk[:-1] + [Wk[-1] + wkk[0]] + wkk[1:] |
380 |
warn = max(warn, warnk)
|
381 |
return Q, Xk, Wk, fcnt, warn
|
382 |
|
383 |
def mytextread0(filename): |
384 |
num = 0
|
385 |
df = file(filename)
|
386 |
df.seek(0)
|
387 |
for line in df: |
388 |
if num == 0: |
389 |
dim = line.strip().split(' ')
|
390 |
row = int(dim[0]) |
391 |
col = int(dim[1]) |
392 |
mat = np.empty([row, col]) |
393 |
else:
|
394 |
data = line.strip().split(' ')
|
395 |
if len(data) == 0 or len(data)== 1: |
396 |
break
|
397 |
else:
|
398 |
for i in range(len(data)): |
399 |
mat[num - 1, i] = float(data[i]) |
400 |
num += 1
|
401 |
return mat
|
402 |
|
403 |
def mytextread1(filename): |
404 |
num = 0
|
405 |
df = file(filename)
|
406 |
df.seek(0)
|
407 |
data = [] |
408 |
for line in df: |
409 |
tmp = line.strip() |
410 |
if len(tmp) != 0: |
411 |
data.append(float(tmp))
|
412 |
else:
|
413 |
break
|
414 |
dim = int(sqrt(len(data))) |
415 |
mat = np.empty([dim, dim]) |
416 |
for i in range(dim): |
417 |
for j in range(dim): |
418 |
mat[i, j] = data[num] |
419 |
num += 1
|
420 |
return mat
|
421 |
|
422 |
def mytextwrite1(filename, mat): |
423 |
num = 0
|
424 |
df = open(filename,'w') |
425 |
df.seek(0)
|
426 |
dim = mat.shape[0]
|
427 |
if dim != mat.shape[1]: |
428 |
print 'matwirte, matrix is not square' |
429 |
for i in range(dim): |
430 |
for j in range(dim): |
431 |
df.write('%20.20e\n'% mat[i, j])
|
432 |
df.close() |