getelec.electron_emitter

Electron emission from metal and semiconductor surfaces.

An emitter wires together four interchangeable pieces:

barrier   -- the spatial potential profile           (potential_barrier)
band      -- which energies to sample                (band_structure)
supply    -- how many electrons arrive at each energy (electron_supply)
solver    -- how likely each one is to tunnel        (transmission_solver)

and turns them into current density, energy distributions, and Nottingham heat.

Two structural points, both of which used to cost real time:

  • The expensive step -- energy grid, supply, transmission -- is computed once and memoised against a fingerprint of every parameter it depends on. Asking for Nottingham heat after the current density no longer redoes the tunnelling calculation, and a fingerprint (rather than a dirty flag) means the cache is still correct if a sub-object is mutated directly.

  • The semiconductor path needs transmission on four energy grids against the same barrier. Those go to the solver as one batched call rather than four separate ones.

class MetalEmitter(_MetalPsiMixin, _EmitterBase):

Thermal-field emission from a metal surface.

Parameters

potential : potential_barrier.Barrier Barrier profile (work function, field, Fermi level). solver : transmission_solver.TransmissionSolver How transmission probabilities are evaluated. supply : electron_supply.Supply Electron supply function. band : band_structure.BandStructure Energy grid generator.

Examples

>>> from getelec import potential_barrier, band_structure  # doctest: +SKIP
>>> from getelec import transmission_solver, electron_supply  # doctest: +SKIP
>>> emitter = MetalEmitter(                                 # doctest: +SKIP
...     potential_barrier.SchottkyPotential(7.5, 4.5, 5.0),
...     transmission_solver.Noumerov(),
...     electron_supply.LogFermiDirac(7.5, 300.0),
...     band_structure.SmartMetal(),
... )
>>> emitter.calculate_current_density()                     # doctest: +SKIP
def calculate_transmission_coefficient(self):

Transmission probability D(E) on the emitter's energy grid.

Returns

energies, transmission : np.ndarray

def calculate_supply_function(self):

Supply function l(E) on the emitter's energy grid, in eV.

Returns

energies, supply : np.ndarray

def calculate_total_energy_distribution(self):

Total energy distribution, in A/(eV cm^2).

TED(E) = R(E) f(E) * integral of D(E_z) dE_z up to E -- the bare occupancy times the transmission integrated over normal energy. See ~getelec.electron_supply.Supply.get_occupancy() for why this uses f while the normal distribution uses l.

R(E) is the band structure's state weight, one everywhere for a free electron gas and so for every band structure but ~getelec.band_structure.DensityOfStatesMetal.

Returns

energies, ted : np.ndarray

def calculate_normal_energy_distribution(self):

Normal energy distribution, in A/(eV cm^2).

NED(E_z) = S(E_z) * D(E_z). For a metal the effective mass equals the free mass, so the transverse window is unrestricted and this is the whole of it.

For a free electron gas S is the log supply l(E_z). When the band structure weights its states -- a tabulated density of states -- the supply is instead integrated over the weighted occupancy above E_z, which is what keeps integral NED dE_z == integral TED dE. See get_weighted_normal_supply().

Returns

energies, ned : np.ndarray

def calculate_current_density(self) -> float:

Emitted current density, in A/cm^2.

Returns

float

def calculate_nottingham_heat(self) -> float:

Nottingham heat P_N, in W/cm^2.

The net power carried away by the emitted electrons relative to the replacement energy, taken at the Fermi level:

P_N = integral of (E - E_F) * TED(E) dE .

Negative means the emitter heats, positive that it cools. An electron leaving from below E_F is replaced by a hotter one at E_F, so cold field emission heats the tip (P_N < 0); at high temperature the emission moves above E_F and the tip cools (P_N > 0).

Returns

float

Notes

Reported in W/cm^2, the same area unit as the current density: the TED is in A/(eV cm^2), so its energy moment is in W/cm^2 directly.

class SemiconductorEmitter(_MetalPsiMixin, _EmitterBase):

Thermal-field emission from a semiconductor surface.

Conduction and valence band channels are treated separately, each with its own effective mass, and summed.

Parameters

potential : potential_barrier.Barrier solver : transmission_solver.TransmissionSolver supply : electron_supply.Supply band : band_structure.Semiconductor

def calculate_psi(self, energies=None, x_points=None):

The wavefunction for each band, on that band's energy grid.

Parameters

energies : tuple of array_like, optional (conduction, valence). Defaults to the emitter's own grids. x_points : array_like, optional Positions in nm, shared by both bands.

Returns

energies_cb, x_cb, psi_cb, energies_vb, x_vb, psi_vb : np.ndarray Each band gets its own spatial grid: the domain is sized to enclose the barrier down to the lowest energy requested, and the two bands start at different energies.

def calculate_probability_current(self, energies=None):

Probability current for each band, on that band's grid.

A stationary scattering state carries a current that does not depend on position, and the Noumerov scheme does not enforce that -- so how much this varies across the grid is an independent check on the integration, band by band.

Returns

energies_cb, x_cb, current_cb, energies_vb, x_vb, current_vb : np.ndarray

def calculate_transmission_coefficient(self):

Transmission for each band, on its own energy grid.

D(E) itself, the tunnelling probability, in [0, 1]. The effective masses do not appear here: they set the window limits of Eq. (8) that calculate_total_energy_distribution() integrates D between.

Returns

energies_cb, trans_cb, energies_vb, trans_vb : np.ndarray

def calculate_window_integrated_transmission(self):

Transmission integrated over the emission window, for each band.

g(E) = integral of D(E_z) dE_z from lower(E) to E, the window of Eq. (8), in eV -- a transmission times the width of the window it was integrated over, so it is not a probability and is not bounded by 1.

Why it exists. calculate_transmission_coefficient() returns D(E), which does not depend on the effective masses at all: the barrier contains no mass. The masses enter only through the limits this integral runs between, so g(E) is the smallest object that shows how the transmission enters the current as the masses change it. A heavier mass opens the window wider and raises g, which is the same direction the current moves in.

TED(E) = f(E) g(E) -- this is the same g the distributions and the current are built from, read out rather than recomputed, so the plotted curve cannot drift from the physics.

Not to be confused with the by-parts integrand g'(E) of Eq. (15), which is negative throughout the valence band for every hole mass and is not returned anywhere.

Returns

energies_cb, window_cb, energies_vb, window_vb : np.ndarray

def calculate_supply_function(self):

Supply function l(E) for each band, on its own energy grid.

Returns

energies_cb, supply_cb, energies_vb, supply_vb : np.ndarray

def calculate_current_density(self) -> float:

Total current density summed over both bands, in A/cm^2.

The integral of the total energy distribution, band by band.

Returns

float

def calculate_total_energy_distribution(self):

Total energy distribution for each band, in A/(eV cm^2).

TED(E) = f(E) * integral of D(E_z) dE_z over the band's window, evaluated directly rather than recovered from its derivative. See _band_window_distributions().

Returns

energies_cb, ted_cb, energies_vb, ted_vb : np.ndarray

def calculate_normal_energy_distribution(self):

Normal energy distribution for each band, in A/(eV cm^2).

NED(E_z) = D(E_z) * [ l(E_z) - l(E_upper) ] -- Stratton Eq. (95) for the valence band, Eq. (49) for the conduction band. Non-negative by construction.

Returned on its own E_z grid, which extends below the total-energy grid. For the conduction band with m_e* > m this puts part of the NED in the band gap, and that is correct: E_z is the normal energy in vacuum, and the conserved parallel momentum carries up to (m_e*/m)(E - E_C) of transverse energy there, more than the electron's whole kinetic energy in the band. Truncating at E_C would lose that part of the current. See the GUIDE section "Semiconductors: the two energy distributions" and _band_window_distributions().

Returns

energies_cb, ned_cb, energies_vb, ned_vb : np.ndarray

def calculate_nottingham_heat(self) -> float:

Nottingham heat P_N summed over both bands, in W/cm^2.

P_N = integral of (E - E_R) * TED(E) dE with the replacement energy E_R at the Fermi level, per Eqs. (13) and (19). Negative means the emitter heats, positive that it cools, exactly as for a metal: an electron leaving from below E_F is replaced by a hotter one.

At low field the valence band leads: electrons leave from below E_F, so the tip heats (P_N < 0). As the field rises the conduction band, above E_F, takes over and the sign flips to cooling (P_N > 0).

Returns

float