getelec.band_structure
Band Structure Calculation Module.
This module provides a suite of classes to model and generate energy grids and band structures for metals and semiconductors: fixed grids, grids trimmed automatically to the energies that carry current ('smart'), and grids supplied by the user ('custom').
Abstract base class representing a material's energy band structure.
Parameters
energy_resolution : float, default 0.01 The step size or resolution for the energy grid discretization, in electron-volts (eV)
Attributes
energy_resolution : float The step size or resolution for the energy grid discretization.
Generate the energy grid or band structure for the material.
Parameters
fermi_level : float The Fermi energy level of the system, in electron-volts (eV) work_function : float The work function of the material, in electron-volts (eV) electric_field : float The applied external electric field, in volts per nanometre (V/nm) temperature : float The thermodynamic temperature of the system, in Kelvin (K)
Returns
numpy.ndarray An array representing the computed energy states or grid.
Raises
NotImplementedError If the subclass does not implement this abstract method, in electron-voltd (eV)
Examples
>>> # Subclasses must implement this method.
>>> # band_structure_instance.generate_band_structure(9.5, 4.5, 0.0, 3.0, 300.0)
How many states each total energy carries, relative to a free electron gas.
The current integral of the paper counts the states available at total
energy E through the inner integral over normal energy, integral of D
dE_z across the window, which for a parabolic band is the area of the
k-parallel disc. A band structure that knows better than the free
electron model returns the ratio here, and the emitter multiplies the
total energy distribution by it; the normal energy distribution is then
rebuilt from the same double integral, so the two still integrate to the
same current density.
The base class returns ones, which is the free electron model and the behaviour of every band structure that does not override this.
Parameters
energy_array : numpy.ndarray Total energies, in eV.
Returns
numpy.ndarray
Dimensionless weights, the same shape as energy_array.
Represents a basic uniform metallic band structure grid.
Parameters
lower_energy_limit : float, default 0.001 The minimum boundary of the uniform energy grid. It represents the bottom of the conduction band and it is the zero for our energy reference system. upper_energy_limit : float, default 30.0 The maximum boundary of the uniform energy grid. It represents the upper limit of the energy grid and it can be above the top of the potential barrier. energy_resolution : float, default 0.01 The discretization step size for the grid.
Attributes
lower_energy_lim : float The minimum boundary of the uniform energy grid. upper_energy_lim : float The maximum boundary of the uniform energy grid. energy_resolution : float The discretization step size for the grid.
Initialize the Metal instance with grid boundaries and resolution.
Generate a uniform energy grid from lower to upper energy limits.
Parameters
**kwargs : dict Arbitrary keyword arguments. Included for compatibility with the base class interface but ignored during calculation.
Returns
numpy.ndarray A 1D array of evenly spaced energy values.
Examples
>>> metal = Metal(lower_energy_limit=0.0, upper_energy_limit=2.0, energy_resolution=0.5)
>>> metal.generate_band_structure()
array([0. , 0.5, 1. , 1.5, 2. ])
Inherited Members
Represents a semiconductor band structure with conduction and valence bands.
Parameters
lower_energy_limit : float, default 0.001 The absolute lowest energy limit for the valence band generation. It represents the bottom of the valence band and it is the zero for our energy reference system. top_valence : float, default 12.5 The energy level corresponding to the top of the valence band. fermi_level : float, default 13.0 The Fermi energy level of the semiconductor system. band_gap : float, default 1.12 The energy band gap separating the valence and conduction bands. electron_eff_mass : float, default 1.64 The effective mass of electrons in the conduction band. It is a float that represents the relative effective mass of the electron when compared with the free electron mass. hole_eff_mass : float, default 0.68 The effective mass of holes in the valence band. It is a float that represents the relative effective mass of the hole when compared with the free electron mass. upper_energy_limit : float, default 30.0 The absolute maximum energy limit for the conduction band generation. energy_resolution : float, default 0.002 The discretization step size for the base grids. Finer than a metal's default because each band's grid ends at its band edge, where the TED has a finite slope: the trapezoid error in the current is then ~(h / k_B T)^2 / 12, about 1.1% at 0.01 eV and 300 K.
Attributes
lower_energy_lim : float The absolute lowest energy limit. upper_energy_lim : float The absolute maximum energy limit. energy_resolution : float The discretization step size. top_valence : float The top of the valence band. fermi_level : float The Fermi energy level. band_gap : float The semiconductor energy band gap. electron_eff_mass : float The effective mass of conduction electrons. hole_eff_mass : float The effective mass of valence holes.
Initialize the Semiconductor instance with full band parameters.
Generate unscaled and scaled dispersion grids for conduction and valence bands.
Parameters
**kwargs : dict Arbitrary keyword arguments. Included for compatibility with the base class interface but ignored during calculation.
Returns
tuple of numpy.ndarray A 4-element tuple containing: - energies_conduction_band1 : Conduction band unscaled energy grid. - energies_conduction_band2 : Conduction band scaled by electron effective mass. - energies_valence_band1 : Valence band unscaled energy grid. - energies_valence_band2 : Valence band scaled by hole effective mass.
Examples
>>> semi = Semiconductor(lower_energy_limit=10.0, top_valence=12.0, band_gap=1.0, upper_energy_limit=14.0, energy_resolution=1.0)
>>> ec1, ec2, ev1, ev2 = semi.generate_band_structure()
Inherited Members
Represents an adaptive metal grid system optimizing energy boundaries dynamically.
Notes
Use only with SN barrier. The rest of the barriers need their own optimisation protocol. If not SN barrier, use Metal or Custom.
The defaults are built for the currents an emitter actually produces. They
hold the current density and the Nottingham heat within 1% of a far wider
grid wherever the current density reaches 1e-12 A/cm^2, which is 1 pA from
1 cm^2 -- checked for the planar, sharp-tip and triangular barriers, work
functions of 2.5 to 6 eV, fields of 0.2 to 12 V/nm and 300 to 3000 K.
Below 1 pA/cm^2 the cuts start to show, and the smaller the current the
more it costs to reach: the same 1% at arbitrarily small currents would
need a supply_threshold around 1e-40 and the energies to match. If
those currents are what you are after, pass a smaller supply_threshold
and a larger barrier_width, or set the limits yourself with
Metal or CustomMetal.
Parameters
barrier_width : float, default 3.0
The spatial width of the potential barrier, beyond which there is effectivively no tunneling.
supply_threshold : float, default 5e-24
The numerical threshold constraint used to cap maximum grid energies, beyond which the emitted electrons do not substatially contribute to the total emitted current.
The cut sits k_B T * ln(1 / supply_threshold) above the Fermi level, 53.7 k_B T at the default. Thermionic emission comes from the top of the barrier, so the grid has to reach it: at 32.2 k_B T (a threshold of 1e-14) the cut falls below the top once the top lies more than about 25 k_B T above the Fermi level, and the current is then underestimated -- by 7% for a 4.5 eV work function at 0.5 V/nm and 1500 K.
energy_resolution : float, default 0.01
The structural resolution step size of the resulting mesh.
Attributes
barrier_width : float The spatial width of the potential barrier. supply_threshold : float The numerical threshold constraint.
Initialize the SmartMetal instance with physical boundary parameters.
Generate an optimized dynamic array grid bounded by the calculated limits.
Parameters
fermi_level : float, default 9.5 The structural Fermi energy level. work_function : float, default 4.5 The target material work function. electric_field : float, default 3.0 External field strength impacting the profile. temperature : float, default 300.0 The thermal setting in Kelvin.
Returns
numpy.ndarray An array containing the structured smart mesh layout.
Examples
>>> sm = SmartMetal()
>>> sm.generate_band_structure(temperature=100.0)
Inherited Members
Semiconductor band grids trimmed with the two criteria of SmartMetal.
The grids of Semiconductor, cut in each band:
- bottom: where the Schottky-Nordheim barrier becomes wider than
barrier_width. As inSmartMetal, a band's grid never starts higher than 1 eV below the top of its occupied states,min(E_F, band top): field emission comes from within a few decay widths of that energy, and at low field the barrier criterion alone would start above it. For the conduction band that is 1 eV belowE_F; for the valence band 1 eV belowmin(E_F, E_V), so a valence band lying more than 1 eV below the Fermi level keeps the energies just belowE_Vit emits from. - top: where the supply
ln(1 + exp(-(E - E_F)/k_B T))falls belowsupply_threshold.
What survives is clipped to each band: the conduction grid never starts
below E_C, and the valence grid never runs past the top of the
Semiconductor valence grid. A band that lies entirely outside the window
comes back empty and contributes nothing -- the conduction band of a
semiconductor at 0 K with the Fermi level in the gap, for example. The
points kept are exactly those of the Semiconductor grids with the same
parameters, so the two agree wherever neither cut applies.
Parameters
lower_energy_limit : float, default 0.001
The bottom of the valence band, and the zero of the energy scale, in eV.
top_valence : float, default 12.5
The top of the valence band, in eV.
fermi_level : float, default 13.0
The Fermi level, in eV. Used when generate_band_structure is not
given one; an emitter passes its barrier's.
band_gap : float, default 1.12
The band gap, in eV.
electron_eff_mass : float, default 1.64
Conduction band effective mass, relative to the free electron mass.
hole_eff_mass : float, default 0.68
Valence band effective mass, relative to the free electron mass.
upper_energy_limit : float, default 30.0
The top of the conduction band grid before trimming, in eV.
energy_resolution : float, default 0.002
The grid step, in eV. See Semiconductor for why it is finer
than a metal's.
barrier_width : float, default 3.0
The barrier width, in nm, below whose energy the transmission is taken
as negligible.
supply_threshold : float, default 5e-24
The supply below which the electrons are taken as negligible. The cut
sits k_B T * ln(1 / supply_threshold) above the Fermi level, 53.7
k_B T at the default, which keeps the barrier top inside the grid
wherever the current reaches 1e-12 A/cm^2. See SmartMetal.
Attributes
lower_energy_lim, upper_energy_lim, energy_resolution : float
As for Semiconductor.
top_valence, fermi_level, band_gap : float
As for Semiconductor.
electron_eff_mass, hole_eff_mass : float
As for Semiconductor.
barrier_width, supply_threshold : float
As for SmartMetal.
Notes
The barrier criterion uses the Schottky-Nordheim barrier, as SmartMetal
does, whatever barrier the emitter holds.
As for SmartMetal, the defaults are set for currents down to
1e-12 A/cm^2 (1 pA from 1 cm^2). For currents far below that, pass a
smaller supply_threshold and a larger barrier_width, or give the
grids yourself with CustomSemiconductor.
Initialize the SmartSemiconductor instance with band and trimming parameters.
Generate the trimmed conduction and valence grids and their window limits.
Parameters
fermi_level : float, optional The Fermi level, in eV. Defaults to the instance's own. work_function : float, default 4.5 The work function, in eV. electric_field : float, default 3.0 The field, in V/nm. temperature : float, default 300.0 The temperature, in K.
Returns
tuple of numpy.ndarray
The same four arrays as Semiconductor.generate_band_structure():
each band's energies and the lower limit of its E_z window. Either
band may be empty.
Examples
>>> smart = SmartSemiconductor(energy_resolution=0.01)
>>> ec1, ec2, ev1, ev2 = smart.generate_band_structure(work_function=4.5, electric_field=5.0, temperature=300.0)
Inherited Members
Represents a static user-provided pre-defined metal band structure system. It can be used to set any arbitrary metallic band structure - the user should be ware of checking for consistency with the other modules
Parameters
custom_energy_array : numpy.ndarray The pre-computed custom structured array representation.
Attributes
custom_energy_array : numpy.ndarray The pre-computed custom structured array representation.
Initialize the CustomMetal tracking containing custom array arrays.
Return the stored custom energy matrix array without transformation.
Parameters
fermi_level : float, default 9.5 Ignored parameters included for subclass compatibility. work_function : float, default 4.5 Ignored parameters included for subclass compatibility. electric_field : float, default 3.0 Ignored parameters included for subclass compatibility. temperature : float, default 300.0 Ignored parameters included for subclass compatibility.
Returns
numpy.ndarray The original initialization array reference map context.
Examples
>>> array = np.array([1, 2, 3])
>>> cm = CustomMetal(array)
>>> cm.generate_band_structure()
array([1, 2, 3])
Inherited Members
A semiconductor band structure on energy grids the user supplies, one per band.
The counterpart of CustomMetal: the energies are returned as given,
for a range, a resolution or a spacing that Semiconductor does not
offer. What a semiconductor needs beyond the energies -- the lower limit of
each energy's E_z window, Eq. (8) of the paper -- follows from the band
edges and effective masses, exactly as in Semiconductor, so the physics
does not depend on which of the two built the grid.
The grids are checked when the band structure is generated, because points
outside a band have no states and would make the distributions
inconsistent: each must be a finite, strictly increasing 1-D array, the
conduction energies must not lie below E_C = top_valence + band_gap, and
the valence energies must not lie above top_valence. Either band may be
empty, and then contributes nothing.
Parameters
custom_conduction_array : array_like Conduction band energies, in eV. custom_valence_array : array_like Valence band energies, in eV. top_valence : float, default 12.5 The top of the valence band, in eV. band_gap : float, default 1.12 The band gap, in eV. electron_eff_mass : float, default 1.64 Conduction band effective mass, relative to the free electron mass. hole_eff_mass : float, default 0.68 Valence band effective mass, relative to the free electron mass.
Attributes
custom_conduction_array, custom_valence_array : numpy.ndarray
The energies of each band.
top_valence, band_gap, electron_eff_mass, hole_eff_mass : float
As for Semiconductor.
Notes
The distributions are verified on uniform grids, which is what the other band structures produce. A non-uniform grid is integrated correctly, but the transmission over each window is sampled at the grid's first step.
Initialize the CustomSemiconductor instance with its band grids and parameters.
Return the stored band grids with the lower limits of their E_z windows.
Parameters
fermi_level, work_function, electric_field, temperature : float Ignored parameters included for subclass compatibility.
Returns
tuple of numpy.ndarray
The same four arrays as Semiconductor.generate_band_structure().
Raises
ValueError If a grid is not a finite, strictly increasing 1-D array, or lies outside its band.
Examples
>>> custom = CustomSemiconductor(np.linspace(13.62, 15.0, 139), np.linspace(11.0, 12.5, 151))
>>> ec1, ec2, ev1, ev2 = custom.generate_band_structure()
Inherited Members
A metal whose energy grid and state count both come from a tabulated density of states.
The other metal band structures assume a free electron gas, whose density of
states goes as sqrt(E) above the bottom of the conduction band. This one
takes g(E) from a table -- a DFT calculation, say -- and weights every
total energy by how many states it actually holds relative to that free
electron reference,
R(E) = [g(E) / sqrt(E)] / [g(E_F) / sqrt(E_F)] ,
normalised so that R(E_F) = 1. The emitter multiplies the total energy
distribution by R and rebuilds the normal energy distribution from the
same double integral, so the current density, the Nottingham heat and both
distributions stay consistent with each other.
The energies are the table's own, so the table sets both the range and the
resolution of the grid. Energies at or below zero are dropped: zero is the
bottom of the conduction band and the reference for every energy in this
package, and 1 / sqrt(E) has no meaning below it.
Parameters
dos_energies : array_like
Energies of the tabulated density of states, in eV, on the same scale as
fermi_level -- that is, measured from the bottom of the conduction
band, not from the Fermi level. Must be finite and strictly increasing.
dos_values : array_like
The density of states at those energies. Any units: only the shape
survives the normalisation, which is why absolute currents remain
comparable to the free electron result even for a projected density of
states with no absolute normalisation of its own.
fermi_level : float
The Fermi level, in eV, measured from the bottom of the conduction band.
Must lie inside the tabulated range, where the table must have states.
work_function : float
The work function, in eV. Used only to check that the grid reaches over
the top of the barrier; the barrier itself holds its own copy.
Attributes
dos_energies, dos_values : numpy.ndarray The table, cropped to positive energies. fermi_level, work_function : float As above. energy_resolution : float The table's own step, taken as the median spacing of its energies.
Notes
What the weight is, and what it is not. In the supply integral the group
velocity cancels the Jacobian, v_z dk_z = dE / hbar, so the quantity that
belongs here is the number of forward-propagating channels at energy E --
the area of the constant energy surface projected on the surface plane,
counted with multiplicity -- and not the density of states, which weights
states by one over the same velocity. Writing R = g / sqrt(E) assumes the
two are related as they are for free electrons. Where flat bands dominate
g they have small normal velocity and small projected area, so their
contribution is overestimated; for a d band metal that is a real effect, not
a rounding one. Treat this as a model of the band structure's influence on
emission rather than as a first-principles calculation of it. If the number
of channels N(E) is known instead, it belongs in the same slot against
its own free electron reference, which goes as E and not as sqrt(E):
get_state_weights() is the only place the ratio is formed.
Range, and where this stops being physics. A table ends where the calculation that produced it ran out of bands, and its density of states falls to zero at that edge for that reason and not a physical one. Emission from the top of a table is therefore an artefact of the band count: the model reports no states where a real metal has a free electron-like continuum, and the current comes out too low.
Field emission is untouched by this, because it draws from within a fraction of an electronvolt of the Fermi level -- on a tabulated d band metal the share of the current density coming from the table's top 1 eV is around 1e-30 at 300 K, at every field from 1.5 to 7 V/nm. Thermionic emission is another matter: it draws from the top of the barrier, which sits close to the end of the table, and the same share reaches 0.99 at 1.5 V/nm and 2000 K, where the tabulated current density comes out 23 times below the free electron one for no physical reason.
So generate_band_structure warns when the top of the table clears the
higher of the barrier maximum and the Fermi level by less than 8 k_B T.
The barrier maximum is the Schottky-Nordheim one,
E_F + phi - 2 sqrt(k_e F / 4), as in SmartMetal. Take the
warning seriously: what it flags is not a discretisation error but a result
set by where the band structure calculation stopped.
Examples
>>> band = DensityOfStatesMetal.from_file( # doctest: +SKIP
... "dos.txt", fermi_level=10.268, work_function=4.67)
>>> energies = band.generate_band_structure() # doctest: +SKIP
>>> weights = band.get_state_weights(energies) # doctest: +SKIP
Initialize the DensityOfStatesMetal instance from a tabulated density of states.
Build the band structure from a two-column text file.
Parameters
path : str or pathlib.Path
A whitespace-separated text file. Header lines and # comments are
skipped, so no row count is needed.
fermi_level, work_function : float
As for the constructor, in eV.
columns : tuple of int, default (0, 1)
Which columns hold the energies and the density of states. Files with
several projections in them are common, so the pair is explicit.
Returns
DensityOfStatesMetal
Examples
>>> band = DensityOfStatesMetal.from_file( # doctest: +SKIP
... "examples/dos.txt", fermi_level=10.268, work_function=4.67)
The ratio R(E) of tabulated to free electron states, normalised to one at E_F.
Zero outside the tabulated range, where the table says there are no
states. Evaluated by interpolation, which is exact on the grid
generate_band_structure() returns, since that is the table's own.
Parameters
energy_array : numpy.ndarray Total energies, in eV.
Returns
numpy.ndarray
The tabulated energies, which set both the range and the resolution of the grid.
Parameters
fermi_level : float, optional The Fermi level, in eV. Defaults to the instance's own. work_function : float, optional The work function, in eV. Defaults to the instance's own. electric_field : float, default 3.0 The field, in V/nm. Used only for the range check. temperature : float, default 300.0 The temperature, in K. Used only for the range check.
Returns
numpy.ndarray The tabulated energies, cropped to positive values.
Warns
RuntimeWarning If the table ends too close to the top of the barrier or to the Fermi level for the emission to be complete. See the class notes.
Examples
>>> band = DensityOfStatesMetal( # doctest: +SKIP
... energies, dos, fermi_level=10.268, work_function=4.67)
>>> band.generate_band_structure(electric_field=5.0, temperature=300.0)