Statistiques
| Révision :

root / ase / dft / stm.py @ 1

Historique | Voir | Annoter | Télécharger (4,71 ko)

1 1 tkerber
from math import exp, sqrt
2 1 tkerber
3 1 tkerber
import numpy as np
4 1 tkerber
5 1 tkerber
from ase.atoms import Atoms
6 1 tkerber
7 1 tkerber
8 1 tkerber
class STM:
9 1 tkerber
    def __init__(self, atoms, symmetries=None):
10 1 tkerber
        if isinstance(atoms, Atoms):
11 1 tkerber
            calc = atoms.get_calculator()
12 1 tkerber
        else:
13 1 tkerber
            calc = atoms
14 1 tkerber
            atoms = calc.get_atoms()
15 1 tkerber
        self.nbands = calc.get_number_of_bands()
16 1 tkerber
        self.weights = calc.get_k_point_weights()
17 1 tkerber
        self.nkpts = len(self.weights)
18 1 tkerber
        self.nspins = calc.get_number_of_spins()
19 1 tkerber
        self.eigs = np.array([[calc.get_eigenvalues(k, s)
20 1 tkerber
                               for k in range(self.nkpts)]
21 1 tkerber
                              for s in range(self.nspins)])
22 1 tkerber
        self.eigs -= calc.get_fermi_level()
23 1 tkerber
        self.calc = calc
24 1 tkerber
        self.cell = atoms.get_cell()
25 1 tkerber
        assert not self.cell[2, :2].any() and not self.cell[:2, 2].any()
26 1 tkerber
        self.ldos = None
27 1 tkerber
        self.symmetries = symmetries or []
28 1 tkerber
29 1 tkerber
    def calculate_ldos(self, width=None):
30 1 tkerber
        if self.ldos is not None and width == self.width:
31 1 tkerber
            return
32 1 tkerber
33 1 tkerber
        if width is None:
34 1 tkerber
            width = 0.1
35 1 tkerber
36 1 tkerber
        ldos = None
37 1 tkerber
        for s in range(self.nspins):
38 1 tkerber
            for k in range(self.nkpts):
39 1 tkerber
                for n in range(self.nbands):
40 1 tkerber
                    psi = self.calc.get_pseudo_wave_function(n, k, s)
41 1 tkerber
                    if ldos is None:
42 1 tkerber
                        ldos = np.zeros_like(psi)
43 1 tkerber
                    f = (exp(-(self.eigs[s, k, n] / width)**2) *
44 1 tkerber
                         self.weights[k])
45 1 tkerber
                    ldos += f * (psi * np.conj(psi)).real
46 1 tkerber
47 1 tkerber
        if 0 in self.symmetries:
48 1 tkerber
            # (x,y) -> (-x,y)
49 1 tkerber
            ldos[1:] += ldos[:0:-1].copy()
50 1 tkerber
            ldos[1:] *= 0.5
51 1 tkerber
52 1 tkerber
        if 1 in self.symmetries:
53 1 tkerber
            # (x,y) -> (x,-y)
54 1 tkerber
            ldos[:, 1:] += ldos[:, :0:-1].copy()
55 1 tkerber
            ldos[:, 1:] *= 0.5
56 1 tkerber
57 1 tkerber
        if 2 in self.symmetries:
58 1 tkerber
            # (x,y) -> (y,x)
59 1 tkerber
            ldos += ldos.transpose((1, 0, 2)).copy()
60 1 tkerber
            ldos *= 0.5
61 1 tkerber
62 1 tkerber
        self.ldos = ldos
63 1 tkerber
        self.width = width
64 1 tkerber
65 1 tkerber
    #def save_ldos(self, filename='ldos.pckl'):
66 1 tkerber
67 1 tkerber
68 1 tkerber
    def get_averaged_current(self, z, width=None):
69 1 tkerber
        self.calculate_ldos(width)
70 1 tkerber
        nz = self.ldos.shape[2]
71 1 tkerber
72 1 tkerber
        # Find grid point:
73 1 tkerber
        n = z / self.cell[2, 2] * nz
74 1 tkerber
        dn = n - np.floor(n)
75 1 tkerber
        n = int(n) % nz
76 1 tkerber
        print n,dn
77 1 tkerber
78 1 tkerber
        # Average and do linear interpolation:
79 1 tkerber
        return ((1 - dn) * self.ldos[:, :, n].mean() +
80 1 tkerber
                dn *       self.ldos[:, :, (n + 1) % nz].mean())
81 1 tkerber
82 1 tkerber
    def scan(self, current, z=None, width=None):
83 1 tkerber
        self.calculate_ldos(width)
84 1 tkerber
85 1 tkerber
        L = self.cell[2, 2]
86 1 tkerber
        if z is None:
87 1 tkerber
            z = L / 2
88 1 tkerber
89 1 tkerber
        nz = self.ldos.shape[2]
90 1 tkerber
        n = int(round(z / L * nz)) % nz
91 1 tkerber
        h = L / nz
92 1 tkerber
93 1 tkerber
        ldos = self.ldos.reshape((-1, nz))
94 1 tkerber
95 1 tkerber
        heights = np.empty(ldos.shape[0])
96 1 tkerber
        for i, a in enumerate(ldos):
97 1 tkerber
            heights[i], z, n = find_height(a, current, z, n, nz, h)
98 1 tkerber
99 1 tkerber
        heights.shape = self.ldos.shape[:2]
100 1 tkerber
        return heights
101 1 tkerber
102 1 tkerber
    def linescan(self, current, p1, p2, npoints=None, z=None, width=None):
103 1 tkerber
        self.calculate_ldos(width)
104 1 tkerber
105 1 tkerber
        L = self.cell[2, 2]
106 1 tkerber
        if z is None:
107 1 tkerber
            z = L / 2
108 1 tkerber
109 1 tkerber
        nz = self.ldos.shape[2]
110 1 tkerber
        n = int(round(z / L * nz)) % nz
111 1 tkerber
        h = L / nz
112 1 tkerber
        ldos = self.ldos.reshape((-1, nz))
113 1 tkerber
114 1 tkerber
        p1 = np.asarray(p1)
115 1 tkerber
        p2 = np.asarray(p2)
116 1 tkerber
        d = p2 - p1
117 1 tkerber
        s = sqrt(np.dot(d, d))
118 1 tkerber
119 1 tkerber
        if npints == None:
120 1 tkerber
            npoints = int(3 * s / h + 2)
121 1 tkerber
122 1 tkerber
        cell = self.cell[:2, :2]
123 1 tkerber
        shape = np.array(self.ldos.shape[:2], float)
124 1 tkerber
        M = cell.I
125 1 tkerber
        heights = np.empty(npoints)
126 1 tkerber
        for i in range(npoints):
127 1 tkerber
            p = p1 + i * d / (npoints - 1)
128 1 tkerber
            q = np.dot(M, p) * shape
129 1 tkerber
            qi = q.astype(int)
130 1 tkerber
            n0, n1 = qi
131 1 tkerber
            f = q - qi
132 1 tkerber
            g = 1 - f
133 1 tkerber
            a = (g[0] * g[0] * ldos[n0,     n1    ] +
134 1 tkerber
                 f[0] * g[0] * ldos[n0 + 1, n1    ] +
135 1 tkerber
                 g[0] * f[0] * ldos[n0,     n1 + 1] +
136 1 tkerber
                 f[0] * f[0] * ldos[n0 + 1, n1 + 1])
137 1 tkerber
            heights[i], z, n = find_height(a, current, z, n, nz, h)
138 1 tkerber
        return np.linspace(0, s, npoints), heights
139 1 tkerber
140 1 tkerber
    def cube(self, filename, atoms=None):
141 1 tkerber
        pass
142 1 tkerber
143 1 tkerber
144 1 tkerber
def find_height(array, current, z, n, nz, h):
145 1 tkerber
    c1 = array[n]
146 1 tkerber
    sign = cmp(c1, current)
147 1 tkerber
    m = 0
148 1 tkerber
    while m < nz:
149 1 tkerber
        n = (n + sign) % nz
150 1 tkerber
        z += sign * h
151 1 tkerber
        c2 = array[n]
152 1 tkerber
        if cmp(c2, current) != sign:
153 1 tkerber
            break
154 1 tkerber
        c1 = c2
155 1 tkerber
        m += 1
156 1 tkerber
157 1 tkerber
    if m == nz:
158 1 tkerber
        print z, n, nz, h, current, array
159 1 tkerber
        raise RuntimeError('Tip crash!')
160 1 tkerber
161 1 tkerber
    return z - sign * h * (current - c2) / (c1 - c2), z, n
162 1 tkerber
163 1 tkerber
164 1 tkerber
165 1 tkerber
166 1 tkerber