root / ase / transport / tools.py @ 7
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() |