root / ase / transport / calculators.py @ 3
Historique | Voir | Annoter | Télécharger (15,15 ko)
1 | 1 | tkerber | import numpy as np |
---|---|---|---|
2 | 1 | tkerber | |
3 | 1 | tkerber | from numpy import linalg |
4 | 1 | tkerber | from ase.transport.selfenergy import LeadSelfEnergy, BoxProbe |
5 | 1 | tkerber | from ase.transport.greenfunction import GreenFunction |
6 | 1 | tkerber | from ase.transport.tools import subdiagonalize, cutcoupling, tri2full, dagger,\ |
7 | 1 | tkerber | rotate_matrix
|
8 | 1 | tkerber | |
9 | 1 | tkerber | |
10 | 1 | tkerber | class TransportCalculator: |
11 | 1 | tkerber | """Determine transport properties of a device sandwiched between
|
12 | 1 | tkerber | two semi-infinite leads using a Green function method.
|
13 | 1 | tkerber | """
|
14 | 1 | tkerber | |
15 | 1 | tkerber | def __init__(self, **kwargs): |
16 | 1 | tkerber | """Create the transport calculator.
|
17 | 1 | tkerber |
|
18 | 1 | tkerber | Parameters
|
19 | 1 | tkerber | ==========
|
20 | 1 | tkerber | h : (N, N) ndarray
|
21 | 1 | tkerber | Hamiltonian matrix for the central region.
|
22 | 1 | tkerber | s : {None, (N, N) ndarray}, optional
|
23 | 1 | tkerber | Overlap matrix for the central region.
|
24 | 1 | tkerber | Use None for an orthonormal basis.
|
25 | 1 | tkerber | h1 : (N1, N1) ndarray
|
26 | 1 | tkerber | Hamiltonian matrix for lead1.
|
27 | 1 | tkerber | h2 : {None, (N2, N2) ndarray}, optional
|
28 | 1 | tkerber | Hamiltonian matrix for lead2. You may use None if lead1 and lead2
|
29 | 1 | tkerber | are identical.
|
30 | 1 | tkerber | s1 : {None, (N1, N1) ndarray}, optional
|
31 | 1 | tkerber | Overlap matrix for lead1. Use None for an orthonomormal basis.
|
32 | 1 | tkerber | hc1 : {None, (N1, N) ndarray}, optional
|
33 | 1 | tkerber | Hamiltonian coupling matrix between the first principal
|
34 | 1 | tkerber | layer in lead1 and the central region.
|
35 | 1 | tkerber | hc2 : {None, (N2, N} ndarray), optional
|
36 | 1 | tkerber | Hamiltonian coupling matrix between the first principal
|
37 | 1 | tkerber | layer in lead2 and the central region.
|
38 | 1 | tkerber | sc1 : {None, (N1, N) ndarray}, optional
|
39 | 1 | tkerber | Overlap coupling matrix between the first principal
|
40 | 1 | tkerber | layer in lead1 and the central region.
|
41 | 1 | tkerber | sc2 : {None, (N2, N) ndarray}, optional
|
42 | 1 | tkerber | Overlap coupling matrix between the first principal
|
43 | 1 | tkerber | layer in lead2 and the central region.
|
44 | 1 | tkerber | energies : {None, array_like}, optional
|
45 | 1 | tkerber | Energy points for which calculated transport properties are
|
46 | 1 | tkerber | evaluated.
|
47 | 1 | tkerber | eta : {1.0e-5, float}, optional
|
48 | 1 | tkerber | Infinitesimal for the central region Green function.
|
49 | 1 | tkerber | eta1/eta2 : {1.0e-5, float}, optional
|
50 | 1 | tkerber | Infinitesimal for lead1/lead2 Green function.
|
51 | 1 | tkerber | align_bf : {None, int}, optional
|
52 | 1 | tkerber | Use align_bf=m to shift the central region
|
53 | 1 | tkerber | by a constant potential such that the m'th onsite element
|
54 | 1 | tkerber | in the central region is aligned to the m'th onsite element
|
55 | 1 | tkerber | in lead1 principal layer.
|
56 | 1 | tkerber | logfile : {None, str}, optional
|
57 | 1 | tkerber | Write a logfile to file with name `logfile`.
|
58 | 1 | tkerber | Use '-' to write to std out.
|
59 | 1 | tkerber | eigenchannels: {0, int}, optional
|
60 | 1 | tkerber | Number of eigenchannel transmission coefficients to
|
61 | 1 | tkerber | calculate.
|
62 | 1 | tkerber | pdos : {None, (N,) array_like}, optional
|
63 | 1 | tkerber | Specify which basis functions to calculate the
|
64 | 1 | tkerber | projected density of states for.
|
65 | 1 | tkerber | dos : {False, bool}, optional
|
66 | 1 | tkerber | The total density of states of the central region.
|
67 | 1 | tkerber | box: XXX
|
68 | 1 | tkerber | YYY
|
69 | 1 | tkerber |
|
70 | 1 | tkerber | If hc1/hc2 are None, they are assumed to be identical to
|
71 | 1 | tkerber | the coupling matrix elements between neareste neighbor
|
72 | 1 | tkerber | principal layers in lead1/lead2.
|
73 | 1 | tkerber |
|
74 | 1 | tkerber | Examples
|
75 | 1 | tkerber | ========
|
76 | 1 | tkerber | >>> import numpy as np
|
77 | 1 | tkerber | >>> h = np.array((0,)).reshape((1,1))
|
78 | 1 | tkerber | >>> h1 = np.array((0, -1, -1, 0)).reshape(2,2)
|
79 | 1 | tkerber | >>> energies = np.arange(-3, 3, 0.1)
|
80 | 1 | tkerber | >>> calc = TransportCalculator(h=h, h1=h1, energies=energies)
|
81 | 1 | tkerber | >>> T = calc.get_transmission()
|
82 | 1 | tkerber |
|
83 | 1 | tkerber | """
|
84 | 1 | tkerber | |
85 | 1 | tkerber | # The default values for all extra keywords
|
86 | 1 | tkerber | self.input_parameters = {'energies': None, |
87 | 1 | tkerber | 'h': None, |
88 | 1 | tkerber | 'h1': None, |
89 | 1 | tkerber | 'h2': None, |
90 | 1 | tkerber | 's': None, |
91 | 1 | tkerber | 's1': None, |
92 | 1 | tkerber | 's2': None, |
93 | 1 | tkerber | 'hc1': None, |
94 | 1 | tkerber | 'hc2': None, |
95 | 1 | tkerber | 'sc1': None, |
96 | 1 | tkerber | 'sc2': None, |
97 | 1 | tkerber | 'box': None, |
98 | 1 | tkerber | 'align_bf': None, |
99 | 1 | tkerber | 'eta1': 1e-5, |
100 | 1 | tkerber | 'eta2': 1e-5, |
101 | 1 | tkerber | 'eta': 1e-5, |
102 | 1 | tkerber | 'logfile': None, # '-', |
103 | 1 | tkerber | 'eigenchannels': 0, |
104 | 1 | tkerber | 'dos': False, |
105 | 1 | tkerber | 'pdos': [],
|
106 | 1 | tkerber | } |
107 | 1 | tkerber | self.initialized = False # Changed Hamiltonians? |
108 | 1 | tkerber | self.uptodate = False # Changed energy grid? |
109 | 1 | tkerber | self.set(**kwargs)
|
110 | 1 | tkerber | |
111 | 1 | tkerber | def set(self, **kwargs): |
112 | 1 | tkerber | for key in kwargs: |
113 | 1 | tkerber | if key in ['h', 'h1', 'h2', 'hc1', 'hc2', |
114 | 1 | tkerber | 's', 's1', 's2', 'sc1', 'sc2', |
115 | 1 | tkerber | 'eta', 'eta1', 'eta2', 'align_bf', 'box']: |
116 | 1 | tkerber | self.initialized = False |
117 | 1 | tkerber | self.uptodate = False |
118 | 1 | tkerber | break
|
119 | 1 | tkerber | elif key in ['energies', 'eigenchannels', 'dos', 'pdos']: |
120 | 1 | tkerber | self.uptodate = False |
121 | 1 | tkerber | elif key not in self.input_parameters: |
122 | 1 | tkerber | raise KeyError, '\'%s\' not a vaild keyword' % key |
123 | 1 | tkerber | |
124 | 1 | tkerber | self.input_parameters.update(kwargs)
|
125 | 1 | tkerber | log = self.input_parameters['logfile'] |
126 | 1 | tkerber | if log is None: |
127 | 1 | tkerber | class Trash: |
128 | 1 | tkerber | def write(self, s): |
129 | 1 | tkerber | pass
|
130 | 1 | tkerber | def flush(self): |
131 | 1 | tkerber | pass
|
132 | 1 | tkerber | self.log = Trash()
|
133 | 1 | tkerber | elif log == '-': |
134 | 1 | tkerber | from sys import stdout |
135 | 1 | tkerber | self.log = stdout
|
136 | 1 | tkerber | elif 'logfile' in kwargs: |
137 | 1 | tkerber | self.log = open(log, 'w') |
138 | 1 | tkerber | |
139 | 1 | tkerber | def initialize(self): |
140 | 1 | tkerber | if self.initialized: |
141 | 1 | tkerber | return
|
142 | 1 | tkerber | |
143 | 1 | tkerber | print >> self.log, '# Initializing calculator...' |
144 | 1 | tkerber | |
145 | 1 | tkerber | p = self.input_parameters
|
146 | 1 | tkerber | if p['s'] == None: |
147 | 1 | tkerber | p['s'] = np.identity(len(p['h'])) |
148 | 1 | tkerber | |
149 | 1 | tkerber | identical_leads = False
|
150 | 1 | tkerber | if p['h2'] == None: |
151 | 1 | tkerber | p['h2'] = p['h1'] # Lead2 is idendical to lead1 |
152 | 1 | tkerber | identical_leads = True
|
153 | 1 | tkerber | |
154 | 1 | tkerber | if p['s1'] == None: |
155 | 1 | tkerber | p['s1'] = np.identity(len(p['h1'])) |
156 | 1 | tkerber | |
157 | 1 | tkerber | if p['s2'] == None and not identical_leads: |
158 | 1 | tkerber | p['s2'] = np.identity(len(p['h2'])) # Orthonormal basis for lead 2 |
159 | 1 | tkerber | else: # Lead2 is idendical to lead1 |
160 | 1 | tkerber | p['s2'] = p['s1'] |
161 | 1 | tkerber | |
162 | 1 | tkerber | |
163 | 1 | tkerber | h_mm = p['h']
|
164 | 1 | tkerber | s_mm = p['s']
|
165 | 1 | tkerber | pl1 = len(p['h1']) / 2 |
166 | 1 | tkerber | pl2 = len(p['h2']) / 2 |
167 | 1 | tkerber | h1_ii = p['h1'][:pl1, :pl1]
|
168 | 1 | tkerber | h1_ij = p['h1'][:pl1, pl1:2 * pl1] |
169 | 1 | tkerber | s1_ii = p['s1'][:pl1, :pl1]
|
170 | 1 | tkerber | s1_ij = p['s1'][:pl1, pl1:2 * pl1] |
171 | 1 | tkerber | h2_ii = p['h2'][:pl2, :pl2]
|
172 | 1 | tkerber | h2_ij = p['h2'][pl2: 2 * pl2, :pl2] |
173 | 1 | tkerber | s2_ii = p['s2'][:pl2, :pl2]
|
174 | 1 | tkerber | s2_ij = p['s2'][pl2: 2 * pl2, :pl2] |
175 | 1 | tkerber | |
176 | 1 | tkerber | if p['hc1'] is None: |
177 | 1 | tkerber | nbf = len(h_mm)
|
178 | 1 | tkerber | h1_im = np.zeros((pl1, nbf), complex)
|
179 | 1 | tkerber | s1_im = np.zeros((pl1, nbf), complex)
|
180 | 1 | tkerber | h1_im[:pl1, :pl1] = h1_ij |
181 | 1 | tkerber | s1_im[:pl1, :pl1] = s1_ij |
182 | 1 | tkerber | p['hc1'] = h1_im
|
183 | 1 | tkerber | p['sc1'] = s1_im
|
184 | 1 | tkerber | else:
|
185 | 1 | tkerber | h1_im = p['hc1']
|
186 | 1 | tkerber | if p['sc1'] is not None: |
187 | 1 | tkerber | s1_im = p['sc1']
|
188 | 1 | tkerber | else:
|
189 | 1 | tkerber | s1_im = np.zeros(h1_im.shape, complex)
|
190 | 1 | tkerber | p['sc1'] = s1_im
|
191 | 1 | tkerber | |
192 | 1 | tkerber | if p['hc2'] is None: |
193 | 1 | tkerber | h2_im = np.zeros((pl2, nbf), complex)
|
194 | 1 | tkerber | s2_im = np.zeros((pl2, nbf), complex)
|
195 | 1 | tkerber | h2_im[-pl2:, -pl2:] = h2_ij |
196 | 1 | tkerber | s2_im[-pl2:, -pl2:] = s2_ij |
197 | 1 | tkerber | p['hc2'] = h2_im
|
198 | 1 | tkerber | p['sc2'] = s2_im
|
199 | 1 | tkerber | else:
|
200 | 1 | tkerber | h2_im = p['hc2']
|
201 | 1 | tkerber | if p['sc2'] is not None: |
202 | 1 | tkerber | s2_im = p['sc2']
|
203 | 1 | tkerber | else:
|
204 | 1 | tkerber | s2_im = np.zeros(h2_im.shape, complex)
|
205 | 1 | tkerber | p['sc2'] = s2_im
|
206 | 1 | tkerber | |
207 | 1 | tkerber | align_bf = p['align_bf']
|
208 | 1 | tkerber | if align_bf != None: |
209 | 1 | tkerber | diff = (h_mm[align_bf, align_bf] - h1_ii[align_bf, align_bf]) \ |
210 | 1 | tkerber | / s_mm[align_bf, align_bf] |
211 | 1 | tkerber | print >> self.log, '# Aligning scat. H to left lead H. diff=', diff |
212 | 1 | tkerber | h_mm -= diff * s_mm |
213 | 1 | tkerber | |
214 | 1 | tkerber | # Setup lead self-energies
|
215 | 1 | tkerber | # All infinitesimals must be > 0
|
216 | 1 | tkerber | assert np.all(np.array((p['eta'], p['eta1'], p['eta2'])) > 0.0) |
217 | 1 | tkerber | self.selfenergies = [LeadSelfEnergy((h1_ii, s1_ii),
|
218 | 1 | tkerber | (h1_ij, s1_ij), |
219 | 1 | tkerber | (h1_im, s1_im), |
220 | 1 | tkerber | p['eta1']),
|
221 | 1 | tkerber | LeadSelfEnergy((h2_ii, s2_ii), |
222 | 1 | tkerber | (h2_ij, s2_ij), |
223 | 1 | tkerber | (h2_im, s2_im), |
224 | 1 | tkerber | p['eta2'])]
|
225 | 1 | tkerber | box = p['box']
|
226 | 1 | tkerber | if box is not None: |
227 | 1 | tkerber | print 'Using box probe!' |
228 | 1 | tkerber | self.selfenergies.append(
|
229 | 1 | tkerber | BoxProbe(eta=box[0], a=box[1], b=box[2], energies=box[3], |
230 | 1 | tkerber | S=s_mm, T=0.3))
|
231 | 1 | tkerber | |
232 | 1 | tkerber | #setup scattering green function
|
233 | 1 | tkerber | self.greenfunction = GreenFunction(selfenergies=self.selfenergies, |
234 | 1 | tkerber | H=h_mm, |
235 | 1 | tkerber | S=s_mm, |
236 | 1 | tkerber | eta=p['eta'])
|
237 | 1 | tkerber | |
238 | 1 | tkerber | self.initialized = True |
239 | 1 | tkerber | |
240 | 1 | tkerber | def update(self): |
241 | 1 | tkerber | if self.uptodate: |
242 | 1 | tkerber | return
|
243 | 1 | tkerber | |
244 | 1 | tkerber | p = self.input_parameters
|
245 | 1 | tkerber | self.energies = p['energies'] |
246 | 1 | tkerber | nepts = len(self.energies) |
247 | 1 | tkerber | nchan = p['eigenchannels']
|
248 | 1 | tkerber | pdos = p['pdos']
|
249 | 1 | tkerber | self.T_e = np.empty(nepts)
|
250 | 1 | tkerber | if p['dos']: |
251 | 1 | tkerber | self.dos_e = np.empty(nepts)
|
252 | 1 | tkerber | if pdos != []:
|
253 | 1 | tkerber | self.pdos_ne = np.empty((len(pdos), nepts)) |
254 | 1 | tkerber | if nchan > 0: |
255 | 1 | tkerber | self.eigenchannels_ne = np.empty((nchan, nepts))
|
256 | 1 | tkerber | |
257 | 1 | tkerber | for e, energy in enumerate(self.energies): |
258 | 1 | tkerber | Ginv_mm = self.greenfunction.retarded(energy, inverse=True) |
259 | 1 | tkerber | lambda1_mm = self.selfenergies[0].get_lambda(energy) |
260 | 1 | tkerber | lambda2_mm = self.selfenergies[1].get_lambda(energy) |
261 | 1 | tkerber | a_mm = linalg.solve(Ginv_mm, lambda1_mm) |
262 | 1 | tkerber | b_mm = linalg.solve(dagger(Ginv_mm), lambda2_mm) |
263 | 1 | tkerber | T_mm = np.dot(a_mm, b_mm) |
264 | 1 | tkerber | if nchan > 0: |
265 | 1 | tkerber | t_n = linalg.eigvals(T_mm).real |
266 | 1 | tkerber | self.eigenchannels_ne[:, e] = np.sort(t_n)[-nchan:]
|
267 | 1 | tkerber | self.T_e[e] = np.sum(t_n)
|
268 | 1 | tkerber | else:
|
269 | 1 | tkerber | self.T_e[e] = np.trace(T_mm).real
|
270 | 1 | tkerber | |
271 | 1 | tkerber | print >> self.log, energy, self.T_e[e] |
272 | 1 | tkerber | self.log.flush()
|
273 | 1 | tkerber | |
274 | 1 | tkerber | if p['dos']: |
275 | 1 | tkerber | self.dos_e[e] = self.greenfunction.dos(energy) |
276 | 1 | tkerber | |
277 | 1 | tkerber | if pdos != []:
|
278 | 1 | tkerber | self.pdos_ne[:, e] = np.take(self.greenfunction.pdos(energy), |
279 | 1 | tkerber | pdos) |
280 | 1 | tkerber | |
281 | 1 | tkerber | self.uptodate = True |
282 | 1 | tkerber | |
283 | 1 | tkerber | def print_pl_convergence(self): |
284 | 1 | tkerber | self.initialize()
|
285 | 1 | tkerber | pl1 = len(self.input_parameters['h1']) / 2 |
286 | 1 | tkerber | |
287 | 1 | tkerber | h_ii = self.selfenergies[0].h_ii |
288 | 1 | tkerber | s_ii = self.selfenergies[0].s_ii |
289 | 1 | tkerber | ha_ii = self.greenfunction.H[:pl1, :pl1]
|
290 | 1 | tkerber | sa_ii = self.greenfunction.S[:pl1, :pl1]
|
291 | 1 | tkerber | c1 = np.abs(h_ii - ha_ii).max() |
292 | 1 | tkerber | c2 = np.abs(s_ii - sa_ii).max() |
293 | 1 | tkerber | print 'Conv (h,s)=%.2e, %2.e' % (c1, c2) |
294 | 1 | tkerber | |
295 | 1 | tkerber | def plot_pl_convergence(self): |
296 | 1 | tkerber | self.initialize()
|
297 | 1 | tkerber | pl1 = len(self.input_parameters['h1']) / 2 |
298 | 1 | tkerber | hlead = self.selfenergies[0].h_ii.real.diagonal() |
299 | 1 | tkerber | hprincipal = self.greenfunction.H.real.diagonal[:pl1]
|
300 | 1 | tkerber | |
301 | 1 | tkerber | import pylab as pl |
302 | 1 | tkerber | pl.plot(hlead, label='lead')
|
303 | 1 | tkerber | pl.plot(hprincipal, label='principal layer')
|
304 | 1 | tkerber | pl.axis('tight')
|
305 | 1 | tkerber | pl.show() |
306 | 1 | tkerber | |
307 | 1 | tkerber | def get_transmission(self): |
308 | 1 | tkerber | self.initialize()
|
309 | 1 | tkerber | self.update()
|
310 | 1 | tkerber | return self.T_e |
311 | 1 | tkerber | |
312 | 1 | tkerber | def get_dos(self): |
313 | 1 | tkerber | self.initialize()
|
314 | 1 | tkerber | self.update()
|
315 | 1 | tkerber | return self.dos_e |
316 | 1 | tkerber | |
317 | 1 | tkerber | def get_eigenchannels(self, n=None): |
318 | 1 | tkerber | """Get ``n`` first eigenchannels."""
|
319 | 1 | tkerber | self.initialize()
|
320 | 1 | tkerber | self.update()
|
321 | 1 | tkerber | if n is None: |
322 | 1 | tkerber | n = self.input_parameters['eigenchannels'] |
323 | 1 | tkerber | return self.eigenchannels_ne[:n] |
324 | 1 | tkerber | |
325 | 1 | tkerber | def get_pdos(self): |
326 | 1 | tkerber | self.initialize()
|
327 | 1 | tkerber | self.update()
|
328 | 1 | tkerber | return self.pdos_ne |
329 | 1 | tkerber | |
330 | 1 | tkerber | def subdiagonalize_bfs(self, bfs, apply=False): |
331 | 1 | tkerber | self.initialize()
|
332 | 1 | tkerber | bfs = np.array(bfs) |
333 | 1 | tkerber | p = self.input_parameters
|
334 | 1 | tkerber | h_mm = p['h']
|
335 | 1 | tkerber | s_mm = p['s']
|
336 | 1 | tkerber | ht_mm, st_mm, c_mm, e_m = subdiagonalize(h_mm, s_mm, bfs) |
337 | 1 | tkerber | if apply: |
338 | 1 | tkerber | self.uptodate = False |
339 | 1 | tkerber | h_mm[:] = ht_mm |
340 | 1 | tkerber | s_mm[:] = st_mm |
341 | 1 | tkerber | # Rotate coupling between lead and central region
|
342 | 1 | tkerber | for alpha, sigma in enumerate(self.selfenergies): |
343 | 1 | tkerber | sigma.h_im[:] = np.dot(sigma.h_im, c_mm) |
344 | 1 | tkerber | sigma.s_im[:] = np.dot(sigma.s_im, c_mm) |
345 | 1 | tkerber | |
346 | 1 | tkerber | c_mm = np.take(c_mm, bfs, axis=0)
|
347 | 1 | tkerber | c_mm = np.take(c_mm, bfs, axis=1)
|
348 | 1 | tkerber | return ht_mm, st_mm, e_m, c_mm
|
349 | 1 | tkerber | |
350 | 1 | tkerber | def cutcoupling_bfs(self, bfs, apply=False): |
351 | 1 | tkerber | self.initialize()
|
352 | 1 | tkerber | bfs = np.array(bfs) |
353 | 1 | tkerber | p = self.input_parameters
|
354 | 1 | tkerber | h_pp = p['h'].copy()
|
355 | 1 | tkerber | s_pp = p['s'].copy()
|
356 | 1 | tkerber | cutcoupling(h_pp, s_pp, bfs) |
357 | 1 | tkerber | if apply: |
358 | 1 | tkerber | self.uptodate = False |
359 | 1 | tkerber | p['h'][:] = h_pp
|
360 | 1 | tkerber | p['s'][:] = s_pp
|
361 | 1 | tkerber | for alpha, sigma in enumerate(self.selfenergies): |
362 | 1 | tkerber | for m in bfs: |
363 | 1 | tkerber | sigma.h_im[:, m] = 0.0
|
364 | 1 | tkerber | sigma.s_im[:, m] = 0.0
|
365 | 1 | tkerber | return h_pp, s_pp
|
366 | 1 | tkerber | |
367 | 1 | tkerber | def lowdin_rotation(self, apply=False): |
368 | 1 | tkerber | p = self.input_parameters
|
369 | 1 | tkerber | h_mm = p['h']
|
370 | 1 | tkerber | s_mm = p['s']
|
371 | 1 | tkerber | eig, rot_mm = linalg.eigh(s_mm) |
372 | 1 | tkerber | eig = np.abs(eig) |
373 | 1 | tkerber | rot_mm = np.dot(rot_mm / np.sqrt(eig), dagger(rot_mm)) |
374 | 1 | tkerber | if apply: |
375 | 1 | tkerber | self.uptodate = False |
376 | 1 | tkerber | h_mm[:] = rotate_matrix(h_mm, rot_mm) # rotate C region
|
377 | 1 | tkerber | s_mm[:] = rotate_matrix(s_mm, rot_mm) |
378 | 1 | tkerber | for alpha, sigma in enumerate(self.selfenergies): |
379 | 1 | tkerber | sigma.h_im[:] = np.dot(sigma.h_im, rot_mm) # rotate L-C coupl.
|
380 | 1 | tkerber | sigma.s_im[:] = np.dot(sigma.s_im, rot_mm) |
381 | 1 | tkerber | |
382 | 1 | tkerber | return rot_mm
|
383 | 1 | tkerber | |
384 | 1 | tkerber | def get_left_channels(self, energy, nchan=1): |
385 | 1 | tkerber | self.initialize()
|
386 | 1 | tkerber | g_s_ii = self.greenfunction.retarded(energy)
|
387 | 1 | tkerber | lambda_l_ii = self.selfenergies[0].get_lambda(energy) |
388 | 1 | tkerber | lambda_r_ii = self.selfenergies[1].get_lambda(energy) |
389 | 1 | tkerber | |
390 | 1 | tkerber | if self.greenfunction.S is None: |
391 | 1 | tkerber | s_s_qsrt_ii = s_s_isqrt = np.identity(len(g_s_ii))
|
392 | 1 | tkerber | else:
|
393 | 1 | tkerber | s_mm = self.greenfunction.S
|
394 | 1 | tkerber | s_s_i, s_s_ii = linalg.eig(s_mm) |
395 | 1 | tkerber | s_s_i = np.abs(s_s_i) |
396 | 1 | tkerber | s_s_sqrt_i = np.sqrt(s_s_i) # sqrt of eigenvalues
|
397 | 1 | tkerber | s_s_sqrt_ii = np.dot(s_s_ii * s_s_sqrt_i, dagger(s_s_ii)) |
398 | 1 | tkerber | s_s_isqrt_ii = np.dot(s_s_ii / s_s_sqrt_i, dagger(s_s_ii)) |
399 | 1 | tkerber | |
400 | 1 | tkerber | lambdab_r_ii = np.dot(np.dot(s_s_isqrt_ii, lambda_r_ii),s_s_isqrt_ii) |
401 | 1 | tkerber | a_l_ii = np.dot(np.dot(g_s_ii, lambda_l_ii), dagger(g_s_ii)) |
402 | 1 | tkerber | ab_l_ii = np.dot(np.dot(s_s_sqrt_ii, a_l_ii), s_s_sqrt_ii) |
403 | 1 | tkerber | lambda_i, u_ii = linalg.eig(ab_l_ii) |
404 | 1 | tkerber | ut_ii = np.sqrt(lambda_i / (2.0 * np.pi)) * u_ii
|
405 | 1 | tkerber | m_ii = 2 * np.pi * np.dot(np.dot(dagger(ut_ii), lambdab_r_ii),ut_ii)
|
406 | 1 | tkerber | T_i,c_in = linalg.eig(m_ii) |
407 | 1 | tkerber | T_i = np.abs(T_i) |
408 | 1 | tkerber | |
409 | 1 | tkerber | channels = np.argsort(-T_i)[:nchan] |
410 | 1 | tkerber | c_in = np.take(c_in, channels, axis=1)
|
411 | 1 | tkerber | T_n = np.take(T_i, channels) |
412 | 1 | tkerber | v_in = np.dot(np.dot(s_s_isqrt_ii, ut_ii), c_in) |
413 | 1 | tkerber | |
414 | 1 | tkerber | return T_n, v_in |