qtcad.device.operators module
Operators represented in solved eigenbases.
The classes in this module build low-dimensional matrix representations of position-dependent operators in the eigenbasis of a device or of another operator.
Currently, only 3D systems are supported.
- class Gate(d: Device | SubDevice | Operator, gate: str | list[str], V: float | list[float], phys_d: Device | None = None, NL: bool = True, params: SolverParams | SolverParams | None = None, base_bias: float | list[float] | None = None)
Bases:
GateRepresent the operator induced by changing gate voltages.
The operator is obtained by deep-copying the physical device, changing the requested gate voltages on the copy, solving the Poisson equation on the copy, and computing the potential change
delta_phirelative to the base configuration. The stored operator isU = +/- e * delta_phi, with the sign set by the confined carrier type:+for holes and-for electrons.- Attributes:
phys_d (device object) – Physical device describing the full system on which the Poisson boundary conditions are enforced.
solver (PoissonSolver) – Poisson solver to be used in the calculation of
U_matrix. It will either be a linear or a non-linear Poisson solver.params (SolverParams) – Solver parameters to pass to the Poisson solver.
Note
Because the
Gateclass is a subclass of theHamiltonianOperatorclass it has the attributes and methods of theHamiltonianOperatorclass in addition to the ones listed here.- __init__(d: Device | SubDevice | Operator, gate: str | list[str], V: float | list[float], phys_d: Device | None = None, NL: bool = True, params: SolverParams | SolverParams | None = None, base_bias: float | list[float] | None = None) None
Initialize a gate-induced Hamiltonian perturbation.
- Parameters:
d – Object providing
mesh,energies, andeigenfunctions. Typically, this is a device for which eigenstates have been computed with the Schrödinger solver. It may also be anotherOperator.gate – Label or labels of the gates whose voltages are modified.
V – Voltage modulation applied to each gate. This input must be consistent with
gate. Ifgateis a string,Vmust be a float giving the voltage applied to that gate. Ifgateis a list of strings,Vmust be a list of floats whose entries give the voltages applied to the corresponding gates.phys_d – Physical device on which the gates are defined. If
None, the physical device is assumed to bed.NL – Whether to use the nonlinear Poisson solver. If
False, the linear Poisson solver is used.params – Solver parameters passed to the Poisson solver.
base_bias – Base bias configuration, giving the gate voltages before the modulation is applied. If
gateis a string,base_biasmust be a float. Ifgateis a list of strings,base_biasmust be a list of floats whose entries correspond to the gates ingate. IfNone, the base configuration stored in the device is used.
- class HamiltonianOperator(d: Device | SubDevice | Operator, U: Callable[[float, float, float], float | complex | ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]])
Bases:
HamiltonianOperatorRepresent an operator used as a perturbation to a Hamiltonian.
A
HamiltonianOperatorrepresents a perturbation \(U\) applied to an unperturbed Hamiltonian \(H_0\). The basiseigenfunctionsis assumed to be the eigenbasis of \(H_0\); \(H_0\) is constructed by placingenergieson the diagonal of a matrix. The perturbation \(U\) is constructed from the matrix elements of the input operator. Thesolvemethod diagonalizes \(H = H_0 + U\) in the input eigenbasis. It can only be called once on a given instance.- Attributes:
eigenfunctions (numpy array) – Eigenfunctions of the system. If
solvehas not been called, this stores the unperturbed eigenfunctions. Ifsolvehas been called, this stores the eigenfunctions after diagonalizing \(H_0 + U\); the input basis is stored ineigenfunctions_old. The first axis runs over mesh nodes, the second over eigenstates, and the third, if present, over bands such as spin, valley, or valence bands.energies (numpy array) – Eigenenergies of the system. If
solvehas not been called, this stores the unperturbed eigenenergies. Ifsolvehas been called, this stores the eigenenergies after diagonalizing \(H_0 + U\); the input eigenenergies are stored inenergies_old.states (numpy array) – 2D array whose columns correspond to the eigenvectors of the perturbed system, i.e. \(H_0 + U\), in the subspace spanned by
eigenfunctions_old. Here \(H_0\) is the matrix withenergies_oldon its diagonal.eigenfunctions_old (numpy array) – Eigenbasis of the system prior to diagonalizing \(H_0 + U\), with the same axis layout as the
eigenfunctionsinput.energies_old (numpy array) – Eigenenergies of the system prior to diagonalizing \(H_0 + U\).
solved (boolean) – Whether
solvehas been called on this object. Callingsolvetwice on the same object is not allowed. To apply another perturbation, construct a new operator from the solved object.
Note
Because
HamiltonianOperatoris a subclass ofOperator, it also provides the attributes and methods inherited fromOperator.- __init__(d: Device | SubDevice | Operator, U: Callable[[float, float, float], float | complex | ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]]) None
Initialize a Hamiltonian perturbation on an eigenbasis.
- Parameters:
d – Object providing
mesh,energies, andeigenfunctions. Typically this is a device for which eigenstates have been computed with the Schrödinger solver. It may also be anotherOperator.U – Hamiltonian perturbation values defined over all global nodes. If
Uis a function, it must take the \(x\), \(y\), and \(z\) coordinates as arguments and return either a scalar for scalar eigenfunctions or a band matrix for eigenfunctions with a band axis. IfUis a NumPy array, it must have shape(nodes,)for scalar eigenfunctions, or shape(nodes, bands, bands)for eigenfunctions with a band axis, wherenodesis the number of global nodes in the mesh.
- solve() None
Compute new energies and eigenstates by diagonalizing \(H_0 + U\).
\(H_0\) is a diagonal matrix with
energieson its diagonal, and \(U\) is the Hamiltonian perturbation matrix. Before diagonalization, \(U\) is validated as Hermitian.This method updates
energiesandeigenfunctionsand stores their pre-solve values inenergies_oldandeigenfunctions_old.- Raises:
RuntimeError – If called more than once on the same object.
ValueError – If the perturbation matrix is not Hermitian.
- class Operator(d: Device | SubDevice | Operator, U: Callable[[float, float, float], float | complex | ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]])
Bases:
OperatorRepresent an operator in a device eigenbasis.
The input basis is usually taken from a
Deviceafter the Schrödinger equation has been solved, but it can also be taken from anotherOperatorobject. Eigenfunctions are expected to have shape(nodes, states)for scalar eigenfunctions or(nodes, states, band)when a band axis is present (bands can refer to spin, valley, or any other components).- Attributes:
eigenfunctions (numpy array) – Eigenfunctions of the system.
energies (numpy array) – Eigenenergies of the system.
mesh (Mesh object) – Mesh over which the eigenfunctions are defined.
local (boolean) – Whether integrals are computed over local tetrahedral nodes. If not, they are computed over global nodes.
multiband (boolean) – Whether the eigenfunctions have a band axis.
U (numpy array) – Operator defined over the mesh.
U_matrix (2D numpy array) – Finite-dimensional matrix representation of
Uin the basis used whenget_operator_matrixis first called.solved (boolean) – Whether
solvehas already been called on this operator object. New operators constructed from solved operators start withsolved = False.
- __init__(d: Device | SubDevice | Operator, U: Callable[[float, float, float], float | complex | ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]]) None
Initialize an operator on a device eigenbasis.
- Parameters:
d – Object providing
mesh,energies, andeigenfunctions. Typically this is aDevicefor which eigenstates have been computed with the Schrödinger solver. Can also be anotherOperatorobject.U – Operator values defined over all global nodes. If
Uis a function, it must take the \(x\), \(y\), and \(z\) coordinates as arguments and return either a scalar for scalar eigenfunctions or a band matrix for eigenfunctions with a band axis. IfUis a NumPy array, it must have shape(nodes,)for scalar eigenfunctions, or shape(nodes, bands, bands)for eigenfunctions with a band axis, wherenodesis the number of global nodes in the mesh.
- get_operator_matrix() ndarray[tuple[Any, ...], dtype[_ScalarT]]
Return the matrix representation of the operator.
If
self.U_matrixalready exists, it is returned unchanged. Otherwise, all matrix elements are computed explicitly in the basis currently stored inself.eigenfunctions, assigned toself.U_matrix, and returned. Changing the attributeseigenfunctions,energies, orUafter this call does not updateself.U_matrix. To represent the same operator in a different basis, construct a new operator from an object that stores that basis.- Returns:
Matrix representation of the operator in the subspace defined by self.eigenfunctions.
- get_operator_matrix_element(i: int, j: int) float | complex
Compute a single matrix element of the operator
U.- Parameters:
i – Row index of the matrix element we wish to compute. Indices are based on the ordering of
self.eigenfunctions.j – Column index of the matrix element we wish to compute. Indices are based on the ordering of
self.eigenfunctions.
- Returns:
Matrix element of the matrix representation of the operator.
Note
Matrix elements are assembled by integrating \(\psi_i^* U \psi_j\). For states with a band axis, band indices are contracted. Here, \(\psi_i\) is given by
self.eigenfunctions[:, i, ...].
- class Zeeman(d: Device | SubDevice | Operator, B: Callable[[float, float, float], ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]], g: Callable[[float, float, float], ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]] | tuple | None = None)
Bases:
ZeemanRepresent the Zeeman operator in a device eigenbasis.
Supported bases are spinless electron eigenstates, two-band electron spin bases, and four-band hole Luttinger-Kohn bases. For spinless electron eigenstates, this operator adds a spin axis before constructing the perturbation.
- Attributes:
B (numpy array) – Magnetic field defined over all global nodes if
self.localisFalse, or over local tetrahedral nodes ifself.localisTrue.g (numpy array) – g-tensor defined over all global nodes if
self.localisFalse, or over local tetrahedral nodes ifself.localisTrue. Only initialized for electron calculations.kappa (numpy array) – Hole Zeeman parameter \(\kappa\) defined over all global nodes if
self.localisFalse, or over local tetrahedral nodes ifself.localisTrue. Only initialized for hole calculations.q (numpy array) – Hole Zeeman parameter \(q\) defined over all global nodes if
self.localisFalse, or over local tetrahedral nodes ifself.localisTrue. Only initialized when specified for hole calculations. If not specified, \(q\) is assumed to be zero at all nodes.eigenfunctions_no_spin (numpy array) – Eigenfunctions before adding the spin index. Only used in spinless electron calculations.
energies_no_spin (numpy array) – Energies before adding the spin index. Only used in spinless electron calculations.
Note
Because
Zeemanis a subclass ofHamiltonianOperator, it also provides the attributes and methods inherited fromHamiltonianOperator.- __init__(d: Device | SubDevice | Operator, B: Callable[[float, float, float], ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]], g: Callable[[float, float, float], ndarray[tuple[Any, ...], dtype[_ScalarT]]] | ndarray[tuple[Any, ...], dtype[_ScalarT]] | tuple | None = None) None
Initialize the Zeeman operator.
- Parameters:
d – Object providing
mesh,energies, andeigenfunctions. Typically, this is a device for which eigenstates have been computed with the Schrödinger solver. It may also be anotherOperator.B – Magnetic field. If callable,
Bmust take the coordinates \(x\), \(y\), and \(z\) as arguments and return the magnetic field at that point.Bmay also be a one-dimensional array of length 3 representing a constant magnetic field, or a two-dimensional array with shape(nodes, 3), wherenodesis the number of global nodes in the mesh.g – Zeeman coupling parameters.
For electrons,
grepresents the g-tensor. If callable, it must take the coordinates \(x\), \(y\), and \(z\) as arguments and return the g-tensor at that point.gmay also be a(3, 3)array representing a constant g-tensor, an array with shape(nodes, 3, 3)for a node-dependent g-tensor, wherenodesis the number of global nodes in the mesh, or, for 3D tetrahedral meshes, a local array with shape(tetra_number, local_node_number, 3, 3). The g-tensor convention is \(H_Z = \mu_B \sum_{i,j} S_i g_{ij} B_j\); the first g-tensor index contracts with the vector of spin operators \(\mathbf{S}=\left(S_x, S_y, S_z\right)\) and the second contracts with the magnetic field \(\mathbf{B}. If ``g`\) isNone, it is taken fromd.get_electron_g_factor().For holes,
gmay be a tuple(kappa, q), wherekappagives the Zeeman coupling to the spin-3/2 matrices \(J_i\) andqgives the Zeeman coupling to the cubed spin-3/2 matrices \(J_i^3\). Ifgis not a tuple, \(q\) is assumed to be zero. IfgisNone,kappaandqare taken fromd.get_hole_Zeeman_params().