Lecture 10.1
Introduction to transport — scattering experiments versus non-equilibrium transport
In the lecture
- what the tunneling lectures of Section 6 computed: a scattering experiment, one wave in, reflection and transmission out, with no bias, no contacts, no temperature and no occupancy of states
- why a device is different: electrons are charged fermions, their occupancy matters, and the current that flows rearranges the very object it flows through
- the new questions this raises: where the electrons are, how the bias changes the charge, the role of spin and of geometry
- what is needed to get a current: channels (can carriers get through?) and a driving force \(\mu_L - \mu_R = eV\) (why would they bother?)
- the window between the two chemical potentials: at zero temperature only it carries net current; at finite temperature excited carriers contribute
In this notebook
you compute the scattering quantities \(T(E)\) and \(R(E)\) of a GaAs/AlGaAs double barrier with open-nemo, show how an applied voltage changes them, build the Landauer current from channels and a driving force (first for ideal channels, which give the conductance quantum, then for the double barrier), and compare the current of the biased device with the current one would predict from the unbiased scattering experiment.
Run it on your own machine
The notebook needs open-nemo (Python ≥ 3.10 and a C++20 compiler; BLAS/LAPACK).
git clone https://github.com/denphi/open-nemo.git && cd open-nemo
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[notebooks]"
jupyter lab From_Atoms_to_Devices/05_introduction_to_transport/10_1_scattering_vs_nonequilibrium_transport.ipynb
Code
import numpy as np
import matplotlib.pyplot as plt
import opennemo as nemo
from opennemo.visualization import style
from opennemo.structures.statistics import fermi
style.use(notebook=True)
EM = nemo.structures.materials.EffectiveMassMaterial
Q, H = nemo.core.units.Q, nemo.core.units.H # C, eV s
G0 = nemo.core.units.G0 # 2e²/h in S
1. What we did before: a scattering experiment#
The tunneling lectures treated a barrier structure the way Rutherford treated a gold foil: send in a wave \(e^{ikz}\) from the left, and measure what comes back, \(r\,e^{-ikz}\), and what goes through, \(t\,e^{ikz}\). The object is characterized by
with \(\hbar\) the reduced Planck constant, \(m^*\) the effective mass, \(V(z)\) the conduction-band profile and \(E_z\) the energy of motion along \(z\). The probe is a weak perturbation: the object is the same after the measurement as before. This is metrology, and the same description applies to electromagnetic waves (refraction, diffraction, transmission), where the photon occupancy never enters. Klimeck stresses what is missing: the problem is purely one-dimensional, with one energy variable; there is no bias, no contact and no temperature; no current is computed; and "we never once asked about the occupancy of states".
The object used throughout this section is a GaAs quantum well of 5 nm between two 5 nm
Al$x$Ga${1-x}$As barriers, 0.3 eV high, with GaAs contacts. The masses are \(0.067\,m_0\) in GaAs and
\(0.092\,m_0\) in the barriers (\(m_0\) the free-electron mass). nemo.resonances returns the
quasi-bound states as complex eigenvalues \(E_r - i\Gamma/2\) of the open system, with \(\Gamma\) the
full width at half maximum of the transmission peak.
Code
gaas = EM("GaAs", 0.067, 12.9)
algaas = EM("AlGaAs", 0.092, 12.2, conduction_band_edge=0.3)
layers = [nemo.Layer(m, d) for m, d in zip((gaas, algaas, gaas, algaas, gaas), (10, 5, 5, 5, 10))]
dev = nemo.Heterostructure1D(layers, spacing=0.05)
tr = nemo.Transport(dev.hamiltonian)
E = np.linspace(0.001, 0.5, 5000)
T = tr.transmission(E)
res0 = nemo.resonances(dev)
for e, g in zip(res0["energy"], res0["width"]):
print(f"resonance at {e * 1e3:6.2f} meV, width Γ = {g * 1e3:.3f} meV")
print(f"smallest R = 1 - T on the grid: {(1 - T).min():.1e}")
fig, axes = plt.subplots(1, 2, figsize=(10, 3.8))
axes[0].plot(dev.x, dev.band_edge, color=style.OPEN_NEMO)
for e in res0["energy"]:
axes[0].axhline(e, color=style.CONTEXT, ls="--", lw=0.8)
axes[0].set(xlabel="z (nm)", ylabel="potential energy (eV)", title="GaAs / AlGaAs double barrier")
axes[1].semilogy(E, T, color=style.OPEN_NEMO, label="T(E)")
axes[1].semilogy(E, 1 - T, color=style.CONTEXT, label="R(E) = 1 − T(E)")
axes[1].set(xlabel="E (eV)", ylabel="probability", ylim=(1e-9, 2), title="scattering experiment")
axes[1].legend(frameon=False, fontsize=8)
fig.tight_layout()
resonance at 81.79 meV, width Γ = 0.129 meV resonance at 292.00 meV, width Γ = 8.989 meV smallest R = 1 - T on the grid: 1.1e-09

Two resonances lie at 81.79 meV and 292.00 meV, with widths of 0.129 meV and 8.99 meV. At a resonance the double barrier transmits with probability one, between them it reflects almost everything. This is everything a scattering experiment can tell: a property of the object, independent of how many electrons are sent in and of whether the states are occupied.
2. Electrons are fermions with charge: transport changes the object#
A device is different. It sits between a source and a drain, and an applied voltage drives a flow of electrons through it. The electrons carry spin and charge, they move and interact. Because they are fermions, the occupancy of the states matters (Fermi functions, Pauli exclusion). And because they are charged, the flow rearranges the potential of the object it flows through: the object is no longer the same after the measurement.
The simplest version of this change, before any charge is computed (that comes in Lectures 10.5 and 10.6), is the applied voltage itself. Assume the voltage \(V\) drops linearly across the two barriers and the well, with flat contacts. The potential energy then falls by \(eV\) from the left to the right contact, and the scattering properties change with it.
Code
def linear_drop(v):
# potential energy (eV): 0 in the left contact, -v in the right one, linear across 10..25 nm
return -v * np.clip((dev.x - dev.x[0] - 10.0) / 15.0, 0, 1)
fig, axes = plt.subplots(1, 2, figsize=(10, 3.8))
print(" V (V) lowest resonance (meV) shift (meV) width (meV) peak T")
for v, c in zip((0.0, 0.05, 0.1), style.sweep(3)):
pot = linear_drop(v)
r = nemo.resonances(dev, potential=pot)
e0, g0 = r["energy"][0], r["width"][0]
peak = tr.transmission(e0 + g0 * np.linspace(-2, 2, 4001), potential=pot).max()
print(f" {v:4.2f} {e0 * 1e3:7.2f} {(e0 - res0['energy'][0]) * 1e3:7.2f}"
f" {g0 * 1e3:.3f} {peak:.3f}")
axes[0].plot(dev.x, dev.band_edge + pot, color=c, label=f"V = {v} V")
Ev = np.linspace(-v + 1e-3, 0.5, 5000)
axes[1].semilogy(Ev, tr.transmission(Ev, potential=pot), color=c, lw=1)
axes[0].set(xlabel="z (nm)", ylabel="potential energy (eV)", title="linear voltage drop")
axes[0].legend(frameon=False, fontsize=8)
axes[1].set(xlabel="E (eV)", ylabel="T(E)", ylim=(1e-9, 2), title="the transmission changes with bias")
fig.tight_layout()
V (V) lowest resonance (meV) shift (meV) width (meV) peak T 0.00 81.79 0.00 0.129 1.000 0.05 56.74 -25.05 0.136 0.857 0.10 31.42 -50.37 0.157 0.532

The lowest resonance moves down by about half the applied voltage (the well sits in the middle of the drop), and the peak transmission falls below one, to 0.53 at 0.1 V, because the biased barriers are no longer equal. The scattering experiment at zero bias does not describe the device under bias. And this is only the externally imposed part: the electrons that tunnel in and pile up in the well add their own charge, and the potential they create must be computed self-consistently. The questions a scattering experiment never asks become central: where are the electrons, \(n(z)\)? Does the flow accumulate or deplete charge? What does the bias do to this charge distribution? What does the geometry do? Klimeck notes that none of these questions exists in the Rutherford experiment, and all of them exist in every real device.
3. What drives transport: channels and a driving force#
To get a current, exactly two ingredients are needed:
- channels: pathways through the structure, each with a transmission probability ("can carriers get through?"). Without channels there is no current, no matter how hard one pushes.
- a driving force: carriers pushed preferentially in one direction ("why would they bother?"). In a device this is the difference of the chemical potentials of the two contacts, \(\mu_L - \mu_R = eV\). Without it there is no net current, no matter how many channels are open.
The Landauer formula combines the two:
with \(e\) the elementary charge, \(h\) Planck's constant, the factor 2 for spin, \(f_{L,R}\) the Fermi
functions of the contacts and \(k_BT\) the thermal energy. The cleanest test is a set of ideal channels,
each with \(T = 1\) above its threshold: at zero temperature each open channel in the window carries
\((2e/h)\,eV\), so the conductance is \(N \cdot 2e^2/h\), with $2e^2/h = 77.5,\mu$S the conductance
quantum. Below, three channels open at 0, 50 and 100 meV, and nemo.landauer_current is compared with
the integral done by hand.
Code
Eg = np.linspace(-0.3, 0.6, 9001)
thresholds = (0.0, 0.05, 0.1)
T3 = sum(fermi(th - Eg, 0.0, 4.0) for th in thresholds) # three smoothed unit steps
def current_by_hand(e, t, mu_l, mu_r, temp):
window = fermi(e, mu_l, temp) - fermi(e, mu_r, temp)
return 2 * Q / H * np.trapezoid(t * window, e) # (2e/h) ∫ T (fL - fR) dE, in A
print(" mu_L (meV) V (mV) T (K) I open-nemo (uA) I by hand (uA) G / (2e²/h)")
for mu, v, temp in ((70, 0, 4), (70, 10, 4), (-100, 10, 4), (70, 10, 300), (120, 10, 4)):
mu_l, mu_r = mu * 1e-3, (mu - v) * 1e-3
I = nemo.landauer_current(Eg, T3, mu_l, mu_r, temp)
Ih = current_by_hand(Eg, T3, mu_l, mu_r, temp)
G = I / (v * 1e-3) / G0 if v else 0.0
print(f" {mu:5d} {v:3d} {temp:4d} {I * 1e6:9.4f} {Ih * 1e6:9.4f}"
f" {G:.3f}")
mu_L (meV) V (mV) T (K) I open-nemo (uA) I by hand (uA) G / (2e²/h)
70 0 4 0.0000 0.0000 0.000
70 10 4 1.5496 1.5496 2.000
-100 10 4 0.0000 0.0000 0.000
70 10 300 1.3724 1.3724 1.771
120 10 4 2.3244 2.3244 3.000With no bias there is no current, even with two channels open (first row). With no open channel in the window, no current flows despite the bias (third row, both chemical potentials 100 meV below the first threshold). With two channels open at \(\mu_L = 70\) meV the conductance is 2.000 conductance quanta at 4 K. At 300 K it is 1.771: the thermal tails, a few times \(k_BT = 26\) meV wide, reach across the thresholds, so the channel opening at 50 meV, only 15–20 meV below the window, counts only partly and the closed channel at 100 meV already contributes. With three channels open at \(\mu_L = 120\) meV the 4 K conductance is 3.000. The library and the hand integral agree.
4. The conceptual picture: two reservoirs and a few channels#
Klimeck's picture of transport has a left reservoir filled up to \(\mu_L\) and a right one filled up to \(\mu_R\), connected by channels with transmissions \(T_1, T_2, T_3\). Below \(\mu_R\) both reservoirs inject equally: left- and right-movers cancel exactly. At zero temperature only the window \([\mu_R, \mu_L]\) carries net current; at finite temperature the window acquires tails of width \(\sim k_BT\) and excited carriers above \(\mu_L\) can carry current too.
For the double barrier, the window is set by contacts with \(\mu_L = 50\) meV above the left conduction-band edge and \(\mu_R = \mu_L - eV\). The current is computed in two ways: with the transmission of the biased structure (linear drop of Section 2), and with the zero-bias transmission of the scattering experiment, kept fixed while only the window opens. The energy grid is uniform with a dense patch of \(\pm 40\,\Gamma\) around every resonance, so that the 0.13 meV wide peak is resolved. The current is per transverse mode (a one-dimensional channel); Lectures 10.7 and 10.8 add the transverse directions.
Code
def grid(pot, v):
r = nemo.resonances(dev, potential=pot)
parts = [np.linspace(-v, 0.5, 2000)] + [e + g * np.linspace(-40, 40, 801)
for e, g in zip(r["energy"], r["width"])]
e = np.unique(np.concatenate(parts))
return e[(e >= -v) & (e <= 0.5)]
mu_l = 0.05
e_fix = grid(None, 0.0)
T_fix = tr.transmission(e_fix)
biases = np.arange(0, 0.301, 0.01)
I_4, I_300, I_fix = [], [], []
for v in biases:
pot = linear_drop(v)
e = grid(pot, v)
Tv = tr.transmission(e, potential=pot)
I_4.append(nemo.landauer_current(e, Tv, mu_l, mu_l - v, 4))
I_300.append(nemo.landauer_current(e, Tv, mu_l, mu_l - v, 300))
I_fix.append(nemo.landauer_current(e_fix, T_fix, mu_l, mu_l - v, 300))
I_4, I_300, I_fix = (np.array(i) * 1e9 for i in (I_4, I_300, I_fix)) # nA
for v in (0.06, 0.08, 0.1, 0.15, 0.2, 0.3):
j = np.argmin(abs(biases - v))
print(f"V = {v:4.2f} V: I(4 K) = {I_4[j]:6.2f} nA, I(300 K) = {I_300[j]:6.2f} nA,"
f" I(300 K, zero-bias T) = {I_fix[j]:5.2f} nA")
V = 0.06 V: I(4 K) = 0.26 nA, I(300 K) = 5.68 nA, I(300 K, zero-bias T) = 3.21 nA V = 0.08 V: I(4 K) = 11.98 nA, I(300 K) = 6.66 nA, I(300 K, zero-bias T) = 3.45 nA V = 0.10 V: I(4 K) = 10.16 nA, I(300 K) = 6.97 nA, I(300 K, zero-bias T) = 3.56 nA V = 0.15 V: I(4 K) = 3.94 nA, I(300 K) = 4.46 nA, I(300 K, zero-bias T) = 3.64 nA V = 0.20 V: I(4 K) = 0.05 nA, I(300 K) = 2.49 nA, I(300 K, zero-bias T) = 3.65 nA V = 0.30 V: I(4 K) = 0.17 nA, I(300 K) = 9.31 nA, I(300 K, zero-bias T) = 3.66 nA
Code
v = 0.1
pot = linear_drop(v)
e = grid(pot, v)
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
ax = axes[0]
ax.semilogx(tr.transmission(e, potential=pot), e, color=style.OPEN_NEMO, lw=1, label="T(E) at 0.1 V")
for temp, ls in ((4, "-"), (300, "--")):
win = fermi(e, mu_l, temp) - fermi(e, mu_l - v, temp)
ax.semilogx(np.maximum(win, 1e-12), e, ls, color=style.REFERENCE, lw=1,
label=f"f_L − f_R, {temp} K")
ax.axhline(mu_l, color=style.CONTEXT, lw=0.6)
ax.axhline(mu_l - v, color=style.CONTEXT, lw=0.6)
ax.set(xlabel="T(E) and window", ylabel="E (eV)", xlim=(1e-6, 2), ylim=(-0.1, 0.25),
title="channel and window at 0.1 V")
ax.legend(frameon=False, fontsize=8, loc="upper left")
ax = axes[1]
ax.plot(biases, I_4, color=style.OPEN_NEMO, label="biased structure, 4 K")
ax.plot(biases, I_300, "--", color=style.OPEN_NEMO, label="biased structure, 300 K")
ax.plot(biases, I_fix, color=style.CONTEXT, label="zero-bias T(E), 300 K")
ax.set(xlabel="bias V (V)", ylabel="current per mode (nA)", title="channels + driving force")
ax.legend(frameon=False, fontsize=8)
fig.tight_layout()

At 4 K the current switches on only once the resonance, which moves down by about \(eV/2\), enters the window below \(\mu_L\): from 81.8 meV it must fall by 31.8 meV, so near 0.064 V, and indeed the current is 0.26 nA at 0.06 V and 12.0 nA at 0.08 V. It switches off when the resonance drops below the conduction-band edge of the left contact, near 0.164 V, and the current falls to 0.05 nA at 0.2 V: negative differential resistance, the signature of a resonant-tunneling diode. At 300 K the thermal tails smear the onset, and the rising current above 0.2 V comes from thermally excited electrons, mainly through the broad second resonance, which the bias pulls down toward \(\mu_L\).
The zero-bias transmission, used with a widening window, gives a current that rises and saturates at 3.66 nA: it never shows the peak and valley, because it ignores that the bias moves the resonance. That is the point of this lecture: in a device, the driving force changes the object, and a transport calculation must compute the object under bias, including (in the following lectures) the charge that the current itself places in it.
Summary#
- A scattering experiment characterizes an object by \(T(E)\) and \(R(E) = 1 - T(E)\); it needs no occupancy, no contacts, no bias and no temperature, and leaves the object unchanged.
- Transport through a device involves charged fermions: occupancy (Fermi functions) matters, and the flow rearranges the potential of the object. Already a linear voltage drop shifts the lowest resonance of the double barrier by about \(eV/2\) and lowers its peak transmission.
- A current needs channels and a driving force \(\mu_L - \mu_R = eV\); the Landauer formula \(I = (2e/h)\int T(f_L - f_R)\,dE\) combines them. Ideal channels give \(2e^2/h\) each.
- At zero temperature only the window \([\mu_R, \mu_L]\) carries net current; at finite temperature excited carriers contribute too.
- The current computed with the biased transmission shows negative differential resistance; the zero-bias transmission does not.
Exercises#
- Move the contact chemical potential from \(\mu_L = 50\) meV to 20 meV and recompute the 4 K I–V curve. Predict the new onset and peak voltages from the \(eV/2\) shift first.
- Replace the linear drop across 10–25 nm by a drop across the right barrier only. How fast does the lowest resonance move with bias now, and how does the I–V change?
- For the three ideal channels, plot the conductance \(I/V\) at \(V = 1\) mV against \(\mu_L\) from \(-50\) to 150 meV at 4 K and 77 K. Where are the steps, and how wide are they?
Further reading#
- Lecture 6.3: the double barrier, the scattering experiment of Section 1 in detail.
- Lecture 10.2: sequential tunneling and Lecture 10.3: coherent tunneling and the Landauer picture.
- Green's functions from scratch and the RTD tutorial.
- R. Landauer, "Spatial variation of currents and fields due to localized scatterers in metallic conduction", IBM J. Res. Dev. 1, 223 (1957).
- S. Datta, Electronic Transport in Mesoscopic Systems (Cambridge University Press, 1995).


