HoppingAmplitudes

See more details about the HoppingAmplitude in the API

# Terminology

Consider the Schrödinger equation

$$i\hbar\frac{d}{dt}|\Psi(t)\rangle = H|\Psi(t)\rangle$$,

and the single-particle Hamiltonian

$$H = \sum_{\mathbf{i}\mathbf{j}}a_{\mathbf{i}\mathbf{j}}c_{\mathbf{i}}^{\dagger}c_{\mathbf{j}}$$.

Using finite differences, the Schrödinger equation can be rewritten as

$$|\Psi(t+dt)\rangle = \left(1 - i\hbar Hdt\right)|\Psi(t)\rangle$$.

In this form, it is clear that $$a_{\mathbf{i}\mathbf{j}}$$ is related to the rate at which single-particle processes move particles from state $$\mathbf{j}$$ to state $$\mathbf{i}$$. Due to TBTK's origin in tight-binding calculations, these parameters are called hopping amplitudes. However, we note that not all $$a_{\mathbf{i}\mathbf{j}}$$ corresponds to the movement of particles. For example, $$a_{\mathbf{i}\mathbf{i}}$$ is related to the rate at which particles are annihilated and immediately recreated in the same state. Likewise, if $$\mathbf{i}$$ and $$\mathbf{j}$$ only differ in a spin index, then the hopping amplitude is related to the rate of a spin-flip process.

The indices $$\mathbf{i}$$ and $$\mathbf{j}$$ are the state in which the particle ends up and starts out, respectively. Therefore they are referred to as to-indices and from-indices, respectively, in TBTK.

# The HoppingAmplitude class

The HoppingAmplitude class represents $$a_{\mathbf{i}\mathbf{j}}$$ and can be created as

HoppingAmplitude hoppingAmplitude(amplitude, toIndex, fromIndex);

Here amplitude is of the type std::complex<double> and toIndex and fromIndex are Indices. However, typically a HoppingAmplitude is created as an argument to a function with explicit Indices written out, in which case it looks more like

... HoppingAmplitude(amplitude, {x+1, y, spin}, {x, y, spin}) ...

Given a HoppingAmplitude, it is possible to extract the amplitude and the to- and from-Indices.

complex<double> amplitude = hoppingAmplitude.getAmplitude();
const Index &toIndex = hoppingAmplitude.getToIndex();
const Index &fromIndex = hoppingAmplitude.getFromIndex();

Sometimes it is useful to delay the specification of a HoppingAmplitudes value. This is, for example, the case when a Model is going to be solved multiple times for different parameter values. Another case is when some of the parameters in the Hamiltonian are to be determined self-consistently. For this reason, it is possible to pass a callback to the HoppingAmplitude instead of a value.

Consider a problem with the Index structure {x, y, spin} and let $$J$$ be a global parameter that determines the strength of a Zeeman term. It is then possible to implement a callback as follows

complex<double> zeemanCallback(
const Index &to,
const Index &from
) const{
//Get spin index.
int spin = from;
//Return the value of the HoppingAmplitude
return -J*(1 - 2*spin);
}

The function zeemanCallback() is responsible for returning the correct value for the given combination of to- and from-Indices. Note that the spin is read from the from-Index. This is because it is assumed that this callback will only be used together with HoppingAmplitudes for which the to- and from-Indices are the same. In general, the implementation of a callback function may involve looking at multiple subindices of both Indices to figure out what to return.

With the callback defined it is possible to create a callback dependent HoppingAmplitude.

HoppingAmplitude up(zeemanCallback, {0, 0, 0}, {0, 0, 0});
HoppingAmplitude down(zeemanCallback, {0, 0, 1}, {0, 0, 1});
J = 1;
Streams::out
<< up.getAmplitude() << "\t"
<< down.getAmplitude() << "\n";
Streams::out << "\n";
J = 2;
Streams::out
<< up.getAmplitude() << "\t"
<< down.getAmplitude() << "\n";

Output:

-1
1
-2
2