Statistiques
| Révision :

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