Révision 1

ase/xrdebye.py (revision 1)
1
from math import exp, pi, sin, sqrt, cos, acos
2
import numpy as np
3

  
4
from ase.data import atomic_numbers
5

  
6
# Table (1) of
7
# D. WAASMAIER AND A. KIRFEL, Acta Cryst. (1995). A51, 416-431
8
waasmaier = {
9
    #      a1        b1         a2        b2        a3        b3          a4         b4         a5         b5        c
10
    'C' : [2.657506, 14.780758, 1.078079, 0.776775, 1.490909, 42.086843,  -4.241070, -0.000294, 0.713791, 0.239535, 4.297983],
11
    'S' : [6.372157, 1.514347, 5.154568, 22.092528, 1.473732, 0.061373,   1.635073,  55.445176, 1.209372, 0.646925, 0.154722],
12
    'Pd': [6.121511, 0.062549,  4.784063, 0.784031, 16.631683, 8.751391,  4.318258, 34.489983, 13.246773, 0.784031, 0.883099],
13
    'Ag': [6.073874, 0.055333, 17.155437, 7.896512, 4.173344, 28.443739,  0.852238, 110.376108, 17.988685, 0.716809, 0.756603],
14
    'Au': [16.777389, 0.122737, 19.317156, 8.621570, 32.979682, 1.256902, 5.595453, 38.008821, 10.576854, 0.000601, -6.279078],
15
    'P' : [1.950541, 0.908139, 4.146930, 27.044953, 1.494560, 0.071280, 1.522042, 67.520190, 5.729711, 1.981173, 0.155233],
16
    'Cl': [1.446071, 0.052357, 6.870609, 1.193165, 6.151801, 18.343416, 1.750347, 46.398394, 0.634168, 0.401005, 0.146773],
17
}
18

  
19
class XrDebye:
20
    def __init__(self, wavelength, alpha=1.01, damping=0.04, warn=True,
21
                 method='Iwasa'):
22
        """
23
        Obtain powder x-ray spectra.
24

  
25
        wavelength in Angstrom
26
        damping in Angstrom**2
27
        """
28
        self.wavelength = wavelength
29
        self.damping = damping
30
        self.alpha = alpha
31
        self.warn = warn
32
        self.method = method
33

  
34
    def set_damping(self, damping):
35
        self.damping = damping
36

  
37
    def get(self, atoms, s):
38
        """Get the powder x-ray (XRD) pattern using the Debye-Formula.
39

  
40
        After: T. Iwasa and K. Nobusada, J. Phys. Chem. C 111 (2007) 45
41
               s is assumed to be in 1/Angstrom
42
        """
43

  
44
        sinth = self.wavelength * s / 2.
45
        costh = sqrt(1. - sinth**2)
46
        cos2th = cos(2. * acos(costh))
47
        pre = exp(- self.damping * s**2 / 2)
48
 
49
        if self.method == 'Iwasa':
50
            pre *= costh / (1. + self.alpha * cos2th**2)
51

  
52
        f = {}
53
        def atomic(symbol):
54
            if not f.has_key(symbol):
55
                if self.method == 'Iwasa':
56
                    f[symbol] = self.get_waasmaier(symbol, s)
57
                else:
58
                    f[symbol] = atomic_numbers[symbol]
59
            return f[symbol]
60

  
61
        def sinc(x):
62
            if x < 1.e-6:
63
                x2 = x * x
64
                return 1 - x2 / 6. + x2 * x2 / 120.
65
            else:
66
                return sin(x) / x
67

  
68
        I = 0.
69
        for a in atoms:
70
            fa = atomic(a.symbol)
71
#            print a.symbol, fa
72
            for b in atoms:
73
                fb = atomic(b.symbol)
74

  
75
                if a == b:
76
                    twopis = 0.
77
                else:
78
                    vrij = a.position - b.position
79
                    rij = np.sqrt(np.dot(vrij, vrij))
80
                    twopisr = 2 * pi * s * rij
81

  
82
                I += fa * fb * sinc(twopisr)
83
                    
84
        return pre * I
85

  
86
    def get_waasmaier(self, symbol, s):
87
        """Scattering factor for free atoms."""
88
        if symbol == 'H':
89
            # XXXX implement analytical H
90
            return 0
91
        elif waasmaier.has_key(symbol):
92
            abc = waasmaier[symbol]
93
            f = abc[10]
94
            s2 = s*s
95
            for i in range(5):
96
                f += abc[2 * i] * exp(-abc[2 * i + 1] * s2)
97
            return f
98
        if self.warn:
99
            print '<xrdebye::get_atomic> Element', symbol, 'not available'
100
        return 0
101
        
ase/units.py (revision 1)
1
from math import pi, sqrt
2

  
3
# Constants from Konrad Hinsen's PhysicalQuantities module:
4
_c = 299792458.              # speed of light, m/s
5
_mu0 = 4.e-7 * pi            # permeability of vacuum
6
_eps0 = 1 / _mu0 / _c**2     # permittivity of vacuum
7
_Grav = 6.67259e-11          # gravitational constant
8
_hplanck = 6.6260755e-34     # Planck constant, J s
9
_hbar = _hplanck / (2 * pi)  # Planck constant / 2pi, J s
10
_e = 1.60217733e-19          # elementary charge
11
_me = 9.1093897e-31          # electron mass
12
_mp = 1.6726231e-27          # proton mass
13
_Nav = 6.0221367e23          # Avogadro number
14
_k = 1.380658e-23            # Boltzmann constant, J/K
15
_amu = 1.6605402e-27         # atomic mass unit, kg
16

  
17
Ang = Angstrom = 1.0
18
nm = 10.0
19
Bohr = 4e10 * pi * _eps0 * _hbar**2 / _me / _e**2  # Bohr radius
20

  
21
eV = 1.0
22
Hartree = _me * _e**3 / 16 / pi**2 / _eps0**2 / _hbar**2
23
kJ = 1000.0 / _e
24
kcal = 4.184 * kJ
25
mol = _Nav
26
Rydberg = 0.5 * Hartree
27
Ry = Rydberg
28
Ha = Hartree
29

  
30
second = 1e10 * sqrt(_e / _amu)
31
fs = 1e-15 * second
32

  
33
kB = _k / _e                 # Boltzmann constant, eV/K
34

  
35
Pascal = (1 / _e) / 1e30  # J/m^3
36
GPa = 1e9 * Pascal
37

  
38
Debye = 1e11 *_e * _c
39

  
40
del pi, sqrt
ase/svnversion_io.py (revision 1)
1
# Copyright (C) 2003  CAMP
2
# Please see the accompanying LICENSE file for further information.
3

  
4
from os import path
5
try:
6
    from subprocess import Popen, PIPE
7
except ImportError:
8
    from os import popen3
9
else:
10
    def popen3(cmd):
11
        p = Popen(cmd, shell=True, close_fds=True,
12
                  stdin=PIPE, stdout=PIPE, stderr=PIPE)
13
        return p.stdin, p.stdout, p.stderr
14

  
15
def write_svnversion(svnversion, dir):
16
    svnversionfile = path.join(dir, 'svnversion.py')
17
    f = open(svnversionfile,'w')
18
    f.write('svnversion = "%s"\n' % svnversion)
19
    f.close()
20
    print 'svnversion = ' +svnversion+' written to '+svnversionfile
21
    # assert svn:ignore property if the installation is under svn control
22
    # because svnversion.py has to be ignored by svn!
23
    cmd = popen3('svn propset svn:ignore svnversion.py '+dir)[1]
24
    output = cmd.read()
25
    cmd.close()
26

  
27
def get_svnversion_from_svn(dir):
28
    # try to get the last svn version number from svnversion
29
    cmd = popen3('svnversion -n '+dir)[1] # assert we are in the project dir
30
    output = cmd.read().strip()
31
    cmd.close()
32
    if output.startswith('exported'):
33
        # we build from exported source (e.g. rpmbuild)
34
        output = None
35
    return output
36

  
37
svnversion = get_svnversion_from_svn(dir='ase')
38
if svnversion:
39
    write_svnversion(svnversion, dir='ase')
ase/neb.py (revision 1)
1
from math import sqrt
2

  
3
import numpy as np
4

  
5
from ase.parallel import world, rank, size
6
from ase.calculators.singlepoint import SinglePointCalculator
7
from ase.io import read
8

  
9
class NEB:
10
    def __init__(self, images, k=0.1, climb=False, parallel=False):
11
        self.images = images
12
        self.k = k
13
        self.climb = climb
14
        self.parallel = parallel
15
        self.natoms = len(images[0])
16
        self.nimages = len(images)
17
        self.emax = np.nan
18

  
19
    def interpolate(self):
20
        pos1 = self.images[0].get_positions()
21
        pos2 = self.images[-1].get_positions()
22
        d = (pos2 - pos1) / (self.nimages - 1.0)
23
        for i in range(1, self.nimages - 1):
24
            self.images[i].set_positions(pos1 + i * d)
25

  
26
    def get_positions(self):
27
        positions = np.empty(((self.nimages - 2) * self.natoms, 3))
28
        n1 = 0
29
        for image in self.images[1:-1]:
30
            n2 = n1 + self.natoms
31
            positions[n1:n2] = image.get_positions()
32
            n1 = n2
33
        return positions
34

  
35
    def set_positions(self, positions):
36
        n1 = 0
37
        for image in self.images[1:-1]:
38
            n2 = n1 + self.natoms
39
            image.set_positions(positions[n1:n2])
40
            n1 = n2
41
        
42
    def get_forces(self):
43
        """Evaluate and return the forces."""
44
        images = self.images
45
        forces = np.empty(((self.nimages - 2), self.natoms, 3))
46
        energies = np.empty(self.nimages - 2)
47

  
48
        if not self.parallel:
49
            # Do all images - one at a time:
50
            for i in range(1, self.nimages - 1):
51
                energies[i - 1] = images[i].get_potential_energy()
52
                forces[i - 1] = images[i].get_forces()
53
        else:
54
            # Parallelize over images:
55
            i = rank * (self.nimages - 2) // size + 1
56
            try:
57
                energies[i - 1] = images[i].get_potential_energy()
58
                forces[i - 1] = images[i].get_forces()
59
            except:
60
                # Make sure other images also fail:
61
                error = world.sum(1.0)
62
                raise
63
            else:
64
                error = world.sum(0.0)
65
                if error:
66
                    raise RuntimeError('Parallel NEB failed!')
67
                
68
            for i in range(1, self.nimages - 1):
69
                root = (i - 1) * size // (self.nimages - 2)
70
                world.broadcast(energies[i - 1:i], root)
71
                world.broadcast(forces[i - 1], root)
72

  
73
        imax = 1 + np.argsort(energies)[-1]
74
        self.emax = energies[imax - 1]
75
        
76
        tangent1 = images[1].get_positions() - images[0].get_positions()
77
        for i in range(1, self.nimages - 1):
78
            tangent2 = (images[i + 1].get_positions() -
79
                        images[i].get_positions())
80
            if i < imax:
81
                tangent = tangent2
82
            elif i > imax:
83
                tangent = tangent1
84
            else:
85
                tangent = tangent1 + tangent2
86
                
87
            tt = np.vdot(tangent, tangent)
88
            f = forces[i - 1]
89
            ft = np.vdot(f, tangent)
90
            if i == imax and self.climb:
91
                f -= 2 * ft / tt * tangent
92
            else:
93
                f -= ft / tt * tangent
94
                f -= (np.vdot(tangent1 - tangent2, tangent) *
95
                      self.k / tt * tangent)
96
                
97
            tangent1 = tangent2
98

  
99
        return forces.reshape((-1, 3))
100

  
101
    def get_potential_energy(self):
102
        return self.emax
103

  
104
    def __len__(self):
105
        return (self.nimages - 2) * self.natoms
106

  
107
class SingleCalculatorNEB(NEB):
108
    def __init__(self, images, k=0.1, climb=False):
109
        if isinstance(images, str):
110
            # this is a filename
111
            traj = read(images, '0:')
112
            images = []
113
            for atoms in traj:
114
                images.append(atoms)
115

  
116
        NEB.__init__(self, images, k, climb, False)
117
        self.calculators = [None] * self.nimages
118
        self.energies_ok = False
119
 
120
    def interpolate(self, initial=0, final=-1):
121
        """Interpolate linearly between initial and final images."""
122
        if final < 0:
123
            final = self.nimages + final
124
        n = final - initial
125
        pos1 = self.images[initial].get_positions()
126
        pos2 = self.images[final].get_positions()
127
        d = (pos2 - pos1) / n
128
        for i in range(1, n):
129
            self.images[initial + i].set_positions(pos1 + i * d)
130

  
131
    def refine(self, steps=1, begin=0, end=-1):
132
        """Refine the NEB trajectory."""
133
        if end < 0:
134
            end = self.nimages + end
135
        j = begin
136
        n = end - begin
137
        for i in range(n):
138
            for k in range(steps):
139
                self.images.insert(j + 1, self.images[j].copy())
140
                self.calculators.insert(j + 1, None)
141
            self.nimages = len(self.images)
142
            self.interpolate(j, j + steps + 1)
143
            j += steps + 1
144

  
145
    def set_positions(self, positions):
146
        # new positions -> new forces
147
        if self.energies_ok:
148
            # restore calculators
149
            self.set_calculators(self.calculators[1:-1])
150
        NEB.set_positions(self, positions)
151

  
152
    def get_calculators(self):
153
        """Return the original calculators."""
154
        calculators = []
155
        for i, image in enumerate(self.images):
156
            if self.calculators[i] is None:
157
                calculators.append(image.get_calculator())
158
            else:
159
                calculators.append(self.calculators[i])
160
        return calculators
161
    
162
    def set_calculators(self, calculators):
163
        """Set new calculators to the images."""
164
        self.energies_ok = False
165

  
166
        if not isinstance(calculators, list):
167
            calculators = [calculators] * self.nimages
168

  
169
        n = len(calculators)
170
        if n == self.nimages:
171
            for i in range(self.nimages):
172
                self.images[i].set_calculator(calculators[i])   
173
        elif n == self.nimages - 2:
174
            for i in range(1, self.nimages -1):
175
                self.images[i].set_calculator(calculators[i-1])   
176
        else:
177
            raise RuntimeError(
178
                'len(calculators)=%d does not fit to len(images)=%d'
179
                % (n, self.nimages))
180

  
181
    def get_energies_and_forces(self, all=False):
182
        """Evaluate energies and forces and hide the calculators"""
183
        if self.energies_ok:
184
            return
185

  
186
        images = self.images
187
        forces = np.zeros(((self.nimages - 2), self.natoms, 3))
188
        energies = np.zeros(self.nimages - 2)
189
        self.emax = -1.e32
190

  
191
        def calculate_and_hide(i):
192
            image = self.images[i]
193
            calc = image.get_calculator()
194
            if self.calculators[i] is None:
195
                self.calculators[i] = calc
196
            if calc is not None:
197
                if not isinstance(calc, SinglePointCalculator):
198
                    self.images[i].set_calculator(
199
                        SinglePointCalculator(image.get_potential_energy(),
200
                                              image.get_forces(),
201
                                              None,
202
                                              None,
203
                                              image))
204
                self.emax = min(self.emax, image.get_potential_energy())
205

  
206
        if all and self.calculators[0] is None:
207
            calculate_and_hide(0)
208

  
209
        # Do all images - one at a time:
210
        for i in range(1, self.nimages - 1):
211
            calculate_and_hide(i)
212

  
213
        if all and self.calculators[-1] is None:
214
            calculate_and_hide(-1)
215

  
216
        self.energies_ok = True
217
       
218
    def get_forces(self):
219
        self.get_energies_and_forces()
220
        return NEB.get_forces(self)
221

  
222
    def n(self):
223
        return self.nimages
224

  
225
    def write(self, filename):
226
        from ase.io.trajectory import PickleTrajectory
227
        traj = PickleTrajectory(filename, 'w', self)
228
        traj.write()
229
        traj.close()
230

  
231
    def __add__(self, other):
232
        for image in other:
233
            self.images.append(image)
234
        return self
235

  
236
def fit(images):
237
    E = [i.get_potential_energy() for i in images]
238
    F = [i.get_forces() for i in images]
239
    R = [i.get_positions() for i in images]
240
    return fit0(E, F, R)
241

  
242
def fit0(E, F, R):
243
    E = np.array(E) - E[0]
244
    n = len(E)
245
    Efit = np.empty((n - 1) * 20 + 1)
246
    Sfit = np.empty((n - 1) * 20 + 1)
247

  
248
    s = [0]
249
    for i in range(n - 1):
250
        s.append(s[-1] + sqrt(((R[i + 1] - R[i])**2).sum()))
251

  
252
    lines = []
253
    for i in range(n):
254
        if i == 0:
255
            d = R[1] - R[0]
256
            ds = 0.5 * s[1]
257
        elif i == n - 1:
258
            d = R[-1] - R[-2]
259
            ds = 0.5 * (s[-1] - s[-2])
260
        else:
261
            d = R[i + 1] - R[i - 1]
262
            ds = 0.25 * (s[i + 1] - s[i - 1])
263

  
264
        d = d / sqrt((d**2).sum())
265
        dEds = -(F[i] * d).sum()
266
        x = np.linspace(s[i] - ds, s[i] + ds, 3)
267
        y = E[i] + dEds * (x - s[i])
268
        lines.append((x, y))
269

  
270
        if i > 0:
271
            s0 = s[i - 1]
272
            s1 = s[i]
273
            x = np.linspace(s0, s1, 20, endpoint=False)
274
            c = np.linalg.solve(np.array([(1, s0,   s0**2,     s0**3),
275
                                          (1, s1,   s1**2,     s1**3),
276
                                          (0,  1,  2 * s0, 3 * s0**2),
277
                                          (0,  1,  2 * s1, 3 * s1**2)]),
278
                                np.array([E[i - 1], E[i], dEds0, dEds]))
279
            y = c[0] + x * (c[1] + x * (c[2] + x * c[3]))
280
            Sfit[(i - 1) * 20:i * 20] = x
281
            Efit[(i - 1) * 20:i * 20] = y
282
        
283
        dEds0 = dEds
284

  
285
    Sfit[-1] = s[-1]
286
    Efit[-1] = E[-1]
287
    return s, E, Sfit, Efit, lines
ase/transport/__init__.py (revision 1)
1
from calculators import TransportCalculator
ase/transport/tools.py (revision 1)
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()
ase/transport/test_transport_calulator.py (revision 1)
1
from ase.transport.calculators import TransportCalculator
2
import numpy as np
3

  
4
#Aux. function to write data to a text file.
5
def write(fname,xs,ys):
6
    fd = open(fname,'w')
7
    for x,y in zip(xs,ys):
8
        print >> fd, x, y
9
    fd.close()
10

  
11
H_lead = np.zeros([4,4])
12

  
13
# On-site energies are zero
14
for i in range(4):
15
    H_lead[i,i] = 0.0
16

  
17
# Nearest neighbor hopping is -1.0
18
for i in range(3):
19
    H_lead[i,i+1] = -1.0
20
    H_lead[i+1,i] = -1.0
21

  
22
# Next-nearest neighbor hopping is 0.2
23
for i in range(2):
24
    H_lead[i,i+2] = 0.2
25
    H_lead[i+2,i] = 0.2
26

  
27
H_scat = np.zeros([6,6])
28
# Principal layers on either side of S
29
H_scat[:2,:2] = H_lead[:2,:2]
30
H_scat[-2:,-2:] = H_lead[:2,:2]
31

  
32
# Scattering region
33
H_scat[2,2] = 0.0
34
H_scat[3,3] = 0.0
35
H_scat[2,3] = -0.8
36
H_scat[3,2] = -0.8
37

  
38
# External coupling
39
H_scat[1,2] = 0.2
40
H_scat[2,1] = 0.2
41
H_scat[3,4] = 0.2
42
H_scat[4,3] = 0.2
43

  
44
energies = np.arange(-3,3,0.02)
45
tcalc = TransportCalculator(h=H_scat,
46
                            h1=H_lead,
47
                            eta=0.02,
48
                            energies=energies)
49

  
50
T = tcalc.get_transmission()
51
tcalc.set(pdos=[2, 3])
52
pdos = tcalc.get_pdos()
53

  
54
tcalc.set(dos=True)
55
dos = tcalc.get_dos()
56

  
57
write('T.dat',tcalc.energies,T)
58
write('pdos0.dat', tcalc.energies,pdos[0])
59
write('pdos1.dat', tcalc.energies,pdos[1])
60

  
61
#subdiagonalize
62
h_rot, s_rot, eps, u = tcalc.subdiagonalize_bfs([2, 3], apply=True)
63
T_rot = tcalc.get_transmission()
64
dos_rot = tcalc.get_dos()
65
pdos_rot = tcalc.get_pdos()
66

  
67
write('T_rot.dat', tcalc.energies,T_rot)
68
write('pdos0_rot.dat', tcalc.energies, pdos_rot[0])
69
write('pdos1_rot.dat', tcalc.energies, pdos_rot[1])
70

  
71
print 'Subspace eigenvalues:', eps
72
assert sum(abs(eps-(-0.8, 0.8))) < 2.0e-15, 'Subdiagonalization. error'
73
print 'Max deviation of T after the rotation:', np.abs(T-T_rot).max()
74
assert max(abs(T-T_rot)) < 2.0e-15, 'Subdiagonalization. error'
75

  
76
#remove coupling
77
h_cut, s_cut = tcalc.cutcoupling_bfs([2], apply=True)
78
T_cut = tcalc.get_transmission()
79
dos_cut = tcalc.get_dos()
80
pdos_cut = tcalc.get_pdos()
81

  
82
write('T_cut.dat', tcalc.energies, T_cut)
83
write('pdos0_cut.dat', tcalc.energies,pdos_cut[0])
84
write('pdos1_cut.dat', tcalc.energies,pdos_cut[1])
85

  
ase/transport/stm_test.py (revision 1)
1
import numpy as np
2
import pylab
3
import ase.transport.stm as stm
4

  
5

  
6
#           Parameters for a simple model.
7
#
8
#                           
9
#                         * eps_a
10
#                 v_ts /   \ v_a2 
11
#  ... *  *  *  *            *  *  *  *  * ...
12
#       \/                          \/
13
#       t1                          t2
14
#
15
#       Tip                      Surface
16
# ----------------|      |-----------------------
17
t1 = -1.0
18
t2 = -2.0
19
eps_a = 0.4
20

  
21
v_ts  = 0.05
22
v_a2 = 1.0
23

  
24
#Tip
25
h1 = np.zeros([2, 2])
26
h1[0, 1] = t1
27
h1[1, 0] = t1
28
s1 = np.identity(2)
29

  
30
h10 = np.zeros([2,2])
31
h10[0, 1] = t1
32
h10[1, 0] = t1
33
s10 = np.identity(2)
34

  
35

  
36
#Surface with "molecule" a.
37
h2 = np.zeros([2,2])
38
h2[0, 1] = v_a2 
39
h2[1, 0] = v_a2
40
h1[0, 0] = eps_a
41
s2 = np.identity(2)
42

  
43
h20 = np.zeros([2,2])
44
h20[0, 1] = t2
45
h20[1, 0] = t2
46
s20 = np.identity(2)
47

  
48

  
49
#Tip Surface coupling
50
V_ts = np.zeros([2,2])
51
V_ts[1, 0] = v_ts
52

  
53
eta1 = 0.0001
54
eta2 = 0.0001
55

  
56
stm = reload(stm)
57
stm_calc = stm.STM(h1, s1, h2, s2, h10, s10, h20, s20, eta1, eta2)
58
energies = np.arange(-3.0, 3.0, 0.01)
59
stm_calc.initialize(energies)
60

  
61

  
62
T_stm = stm_calc.get_transmission(V_ts)
63

  
64

  
65
#Perform the full calculation and compare
66
from ase.transport.calculators import TransportCalculator as TC
67

  
68
h = np.zeros([4,4])
69
h[:2, :2] = h1
70
h[-2:, -2:] = h2
71
h[:2, -2:] = V_ts
72
h[-2:, :2] = V_ts.T
73

  
74

  
75
tc = TC(energies=energies,
76
        h=h,
77
        h1=h10,
78
        h2=h20,
79
        eta=eta1, eta1=eta1, eta2=eta2)
80
        
81
T_full = tc.get_transmission()
82

  
83
pylab.plot(stm_calc.energies, T_stm, 'b')
84
pylab.plot(tc.energies, T_full, 'r--')
85
pylab.show()
86

  
87

  
88
#bias stuff
89
biass = np.arange(-2.0, 2.0, 0.2)
90
Is = [stm_calc.get_current(bias, V_ts) for bias in biass]
91
pylab.plot(biass, Is, '+')
92
pylab.show()
93

  
94

  
ase/transport/selfenergy.py (revision 1)
1
import numpy as np
2

  
3

  
4
class LeadSelfEnergy:
5
    conv = 1e-8 # Convergence criteria for surface Green function
6
    
7
    def __init__(self, hs_dii, hs_dij, hs_dim, eta=1e-4):
8
        self.h_ii, self.s_ii = hs_dii # onsite principal layer
9
        self.h_ij, self.s_ij = hs_dij # coupling between principal layers
10
        self.h_im, self.s_im = hs_dim # coupling to the central region
11
        self.nbf = self.h_im.shape[1] # nbf for the scattering region
12
        self.eta = eta
13
        self.energy = None
14
        self.bias = 0
15
        self.sigma_mm = np.empty((self.nbf, self.nbf), complex)
16
    
17
    def retarded(self, energy):
18
        """Return self-energy (sigma) evaluated at specified energy."""
19
        if energy != self.energy:
20
            self.energy = energy
21
            z = energy - self.bias + self.eta * 1.j           
22
            tau_im = z * self.s_im - self.h_im
23
            a_im = np.linalg.solve(self.get_sgfinv(energy), tau_im)
24
            tau_mi = z * self.s_im.T.conj() - self.h_im.T.conj()
25
            self.sigma_mm[:] = np.dot(tau_mi, a_im)
26

  
27
        return self.sigma_mm
28

  
29
    def set_bias(self, bias):
30
        self.bias = bias
31

  
32
    def get_lambda(self, energy):
33
        """Return the lambda (aka Gamma) defined by i(S-S^d).
34

  
35
        Here S is the retarded selfenergy, and d denotes the hermitian
36
        conjugate.
37
        """
38
        sigma_mm = self.retarded(energy)
39
        return 1.j * (sigma_mm - sigma_mm.T.conj())
40
        
41
    def get_sgfinv(self, energy):
42
        """The inverse of the retarded surface Green function""" 
43
        z = energy - self.bias + self.eta * 1.j
44
        
45
        v_00 = z * self.s_ii.T.conj() - self.h_ii.T.conj()
46
        v_11 = v_00.copy()
47
        v_10 = z * self.s_ij - self.h_ij
48
        v_01 = z * self.s_ij.T.conj() - self.h_ij.T.conj()
49

  
50
        delta = self.conv + 1
51
        while delta > self.conv:
52
            a = np.linalg.solve(v_11, v_01)
53
            b = np.linalg.solve(v_11, v_10)
54
            v_01_dot_b = np.dot(v_01, b)
55
            v_00 -= v_01_dot_b
56
            v_11 -= np.dot(v_10, a) 
57
            v_11 -= v_01_dot_b
58
            v_01 = -np.dot(v_01, a)
59
            v_10 = -np.dot(v_10, b)
60
            delta = abs(v_01).max()
61

  
62
        return v_00
63

  
64

  
65
class BoxProbe:
66
    """Box shaped Buttinger probe.
67
    
68
    Kramers-kroning: real = H(imag); imag = -H(real)
69
    """
70
    def __init__(self, eta, a, b, energies, S, T=0.3):
71
        from Transport.Hilbert import hilbert
72
        se = np.empty(len(energies), complex)
73
        se.imag = .5 * (np.tanh(.5 * (energies - a) / T) -
74
                        np.tanh(.5 * (energies - b) / T))
75
        se.real = hilbert(se.imag)
76
        se.imag -= 1
77
        self.selfenergy_e = eta * se
78
        self.energies = energies
79
        self.S = S
80
    
81
    def retarded(self, energy):
82
        return self.selfenergy_e[self.energies.searchsorted(energy)] * self.S
83
        
ase/transport/stm.py (revision 1)
1
import numpy as np
2
from ase.transport.tools import dagger
3
from ase.transport.selfenergy import LeadSelfEnergy
4
from ase.transport.greenfunction import GreenFunction
5
import time
6
from gpaw.mpi import world
7

  
8

  
9
class STM:
10
    def __init__(self, h1, s1, h2, s2 ,h10, s10, h20, s20, eta1, eta2, w=0.5, pdos=[], logfile = None):
11
        """XXX
12
        
13
        1. Tip
14
        2. Surface
15
        
16
        h1: ndarray
17
            Hamiltonian and overlap matrix for the isolated tip
18
            calculation.  Note, h1 should contain (at least) one
19
            principal layer.
20

  
21
        h2: ndarray
22
            Same as h1 but for the surface.
23

  
24
        h10: ndarray
25
            periodic part of the tip. must include two and only
26
            two principal layers.
27

  
28
        h20: ndarray
29
            same as h10, but for the surface
30

  
31
        The s* are the corresponding overlap matrices.  eta1, and eta
32
        2 are (finite) infinitesimals.  """
33
        
34
        self.pl1 = len(h10) // 2 #principal layer size for the tip
35
        self.pl2 = len(h20) // 2 #principal layer size for the surface
36
        self.h1 = h1 
37
        self.s1 = s1
38
        self.h2 = h2
39
        self.s2 = s2
40
        self.h10 = h10 
41
        self.s10 = s10 
42
        self.h20 = h20 
43
        self.s20 = s20
44
        self.eta1 = eta1
45
        self.eta2 = eta2
46
        self.w = w #asymmetry of the applied bias (0.5=>symmetric)
47
        self.pdos = []
48
        self.log = logfile
49

  
50
    def initialize(self, energies, bias=0):
51
        """
52
            energies: list of energies 
53
            for which the transmission function should be evaluated.
54
            bias.
55
            Will precalculate the surface greenfunctions of the tip and
56
            surface.
57
        """
58
        self.bias = bias
59
        self.energies = energies
60
        nenergies = len(energies)
61
        pl1, pl2 = self.pl1, self.pl2
62
        nbf1, nbf2 = len(self.h1), len(self.h2)
63
      
64
        #periodic part of the tip
65
        hs1_dii = self.h10[:pl1, :pl1], self.s10[:pl1, :pl1]
66
        hs1_dij = self.h10[:pl1, pl1:2*pl1], self.s10[:pl1, pl1:2*pl1]
67
        #coupling betwen per. and non. per part of the tip
68
        h1_im = np.zeros((pl1, nbf1), complex) 
69
        s1_im = np.zeros((pl1, nbf1), complex)
70
        h1_im[:pl1, :pl1], s1_im[:pl1, :pl1] = hs1_dij
71
        hs1_dim = [h1_im, s1_im]
72

  
73
        #periodic part the surface 
74
        hs2_dii = self.h20[:pl2, :pl2], self.s20[:pl2, :pl2]
75
        hs2_dij = self.h20[pl2:2*pl2, :pl2], self.s20[pl2:2*pl2, :pl2]
76
        #coupling betwen per. and non. per part of the surface
77
        h2_im = np.zeros((pl2, nbf2), complex)
78
        s2_im = np.zeros((pl2, nbf2), complex) 
79
        h2_im[-pl2:, -pl2:], s2_im[-pl2:, -pl2:] = hs2_dij
80
        hs2_dim = [h2_im, s2_im]
81

  
82
        #tip and surface greenfunction 
83
        self.selfenergy1 = LeadSelfEnergy(hs1_dii, hs1_dij, hs1_dim, self.eta1)
84
        self.selfenergy2 = LeadSelfEnergy(hs2_dii, hs2_dij, hs2_dim, self.eta2)
85
        self.greenfunction1 = GreenFunction(self.h1-self.bias*self.w*self.s1, self.s1, 
86
                                            [self.selfenergy1], self.eta1)
87
        self.greenfunction2 = GreenFunction(self.h2-self.bias*(self.w-1)*self.s2, self.s2, 
88
                                            [self.selfenergy2], self.eta2)
89
        
90
        #Shift the bands due to the bias.
91
        bias_shift1 = -bias * self.w
92
        bias_shift2 = -bias * (self.w - 1)
93
        self.selfenergy1.set_bias(bias_shift1)
94
        self.selfenergy2.set_bias(bias_shift2)
95
        
96
        #tip and surface greenfunction matrices.
97
        nbf1_small = nbf1 #XXX Change this for efficiency in the future
98
        nbf2_small = nbf2 #XXX -||-
99
        coupling_list1 = range(nbf1_small)# XXX -||-
100
        coupling_list2 = range(nbf2_small)# XXX -||-
101
        self.gft1_emm = np.zeros((nenergies, nbf1_small, nbf1_small), complex) 
102
        self.gft2_emm = np.zeros((nenergies, nbf2_small, nbf2_small), complex)
103
 
104
        for e, energy in enumerate(self.energies):
105
            if self.log != None: # and world.rank == 0:
106
                    T = time.localtime()
107
                    self.log.write(' %d:%02d:%02d, ' % (T[3], T[4], T[5]) +
108
                                   '%d, %d, %02f\n' % (world.rank, e, energy))
109
            gft1_mm = self.greenfunction1.retarded(energy)[coupling_list1]
110
            gft1_mm = np.take(gft1_mm, coupling_list1, axis=1)
111

  
112
            gft2_mm = self.greenfunction2.retarded(energy)[coupling_list2]
113
            gft2_mm = np.take(gft2_mm, coupling_list2, axis=1)
114
 
115
            self.gft1_emm[e] = gft1_mm
116
            self.gft2_emm[e] = gft2_mm
117

  
118
            if self.log != None and world.rank == 0:
119
                self.log.flush()
120

  
121
    def get_transmission(self, v_12, v_11_2=None, v_22_1=None):
122
        """XXX
123

  
124
        v_12:
125
            coupling between tip and surface 
126
        v_11_2:
127
            correction to "on-site" tip elements due to the 
128
            surface (eq.16). Is only included to first order.
129
        v_22_1:
130
            corretion to "on-site" surface elements due to he
131
            tip (eq.17). Is only included to first order.
132
        """
133

  
134
        dim0 = v_12.shape[0]
135
        dim1 = v_12.shape[1]
136

  
137
        nenergies = len(self.energies)
138
        T_e = np.empty(nenergies,float)
139
        v_21 = dagger(v_12)
140
        for e, energy in enumerate(self.energies):
141
            gft1 = self.gft1_emm[e]
142
            if v_11_2!=None:
143
                gf1 = np.dot(v_11_2, np.dot(gft1, v_11_2)) 
144
                gf1 += gft1 #eq. 16
145
            else:
146
                gf1 = gft1
147
            
148
            gft2 = self.gft2_emm[e]
149
            if v_22_1!=None:
150
                gf2 = np.dot(v_22_1,np.dot(gft2, v_22_1))
151
                gf2 += gft2 #eq. 17
152
            else:
153
                gf2 = gft2
154
            
155
            a1 = (gf1 - dagger(gf1))
156
            a2 = (gf2 - dagger(gf2))
157
            self.v_12 = v_12
158
            self.a2 = a2
159
            self.v_21 = v_21
160
            self.a1 = a1
161
            v12_a2 = np.dot(v_12, a2[:dim1])
162
            v21_a1 = np.dot(v_21, a1[-dim0:])
163
            self.v12_a2 = v12_a2
164
            self.v21_a1 = v21_a1
165
            T = -np.trace(np.dot(v12_a2[:,:dim1], v21_a1[:,-dim0:])) #eq. 11
166
            T_e[e] = T
167
            self.T_e = T_e
168
        return T_e
169

  
170

  
171
    def get_current(self, bias, v_12, v_11_2=None, v_22_1=None):
172
        """Very simple function to calculate the current.
173
        
174
        Asummes zero temperature.
175

  
176
        bias: type? XXX
177
            bias voltage (V)
178
            
179
        v_12: XXX
180
            coupling between tip and surface.
181
            
182
        v_11_2:
183
            correction to onsite elements of the tip
184
            due to the potential of the surface.
185
        v_22_1:
186
            correction to onsite elements of the surface
187
            due to the potential of the tip.
188
        """
189
        energies = self.energies
190
        T_e = self.get_transmission(v_12, v_11_2, v_22_1)
191
        bias_window = -np.array([bias * self.w, bias * (self.w - 1)])
192
        bias_window.sort()
193
        self.bias_window = bias_window
194
        #print 'bias window', np.around(bias_window,3)
195
        #print 'Shift of tip lead do to the bias:', self.selfenergy1.bias
196
        #print 'Shift of surface lead do to the bias:', self.selfenergy2.bias
197
        i1 = sum(energies < bias_window[0]) 
198
        i2 = sum(energies < bias_window[1])
199
        step = 1 
200
        if i2 < i1:
201
            step = -1
202
        
203
        return np.sign(bias)*np.trapz(x=energies[i1:i2:step], y=T_e[i1:i2:step])
204

  
205

  
206

  
207

  
208

  
209

  
ase/transport/greenfunction.py (revision 1)
1
import numpy as np
2

  
3
class GreenFunction:
4
    """Equilibrium retarded Green function."""
5
    
6
    def __init__(self, H, S=None, selfenergies=[], eta=1e-4):
7
        self.H = H
8
        self.S = S
9
        self.selfenergies = selfenergies
10
        self.eta = eta
11
        self.energy = None
12
        self.Ginv = np.empty(H.shape, complex)
13

  
14
    def retarded(self, energy, inverse=False):
15
        """Get retarded Green function at specified energy.
16

  
17
        If 'inverse' is True, the inverse Green function is returned (faster).
18
        """
19
        if energy != self.energy:
20
            self.energy = energy
21
            z = energy + self.eta * 1.j
22

  
23
            if self.S is None:
24
                self.Ginv[:] = 0.0
25
                self.Ginv.flat[:: len(self.S) + 1] = z
26
            else:
27
                self.Ginv[:] = z
28
                self.Ginv *= self.S
29
            self.Ginv -= self.H
30

  
31
            for selfenergy in self.selfenergies:
32
                self.Ginv -= selfenergy.retarded(energy)
33

  
34
        if inverse:
35
            return self.Ginv
36
        else:
37
            return np.linalg.inv(self.Ginv)
38

  
39
    def calculate(self, energy, sigma):
40
        """XXX is this really needed"""
41
        ginv = energy * self.S - self.H - sigma 
42
        return np.linalg.inv(ginv)
43

  
44
    def apply_retarded(self, energy, X):
45
        """Apply retarded Green function to X.
46
        
47
        Returns the matrix product G^r(e) . X
48
        """
49
        return np.linalg.solve(self.retarded(energy, inverse=True), X)
50

  
51
    def dos(self, energy):
52
        """Total density of states -1/pi Im(Tr(GS))"""
53
        if self.S is None:
54
            return -self(energy).imag.trace() / np.pi
55
        else:
56
            GS = self.apply_retarded(energy, self.S)
57
            return -GS.imag.trace() / np.pi
58
        
59
    def pdos(self, energy):
60
        """Projected density of states -1/pi Im(SGS/S)"""
61
        if self.S is None:
62
            return -self.retarded(energy).imag.diagonal() / np.pi
63
        else:
64
            S = self.S
65
            SGS = np.dot(S, self.apply_retarded(energy, S))
66
            return -(SGS.diagonal() / S.diagonal()).imag / np.pi
ase/transport/calculators.py (revision 1)
1
import numpy as np
2

  
3
from numpy import linalg
4
from ase.transport.selfenergy import LeadSelfEnergy, BoxProbe
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff