HoppingAmplitudes

See more details about the HoppingAmplitude in the API

Consider the SchrÃ¶dinger equation

and the single-particle Hamiltonian

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

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 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 parameter that determines the strength of a Zeeman term. It is then possible to implement a callback as follows

class ZeemanCallback : public HoppingAmplitude::AmplitudeCallback{

public:

complex<double> getHoppingAmplitude(

const Index &to,

const Index &from

) const{

//Get spin index.

int spin = from[2];

//Return the value of the HoppingAmplitude

return -J*(1 - 2*spin);

}

void setJ(complex<double> J){

this->J = J;

}

private:

double J;

}

Here the function *getHoppingAmplitude()* 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 *getHoppingAmplitude()* may involve looking at multiple Subindices of both Indices to figure out what to return. Finally, the *setJ()* function allows for the J value to be changed.

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

ZeemanCallback zeemanCallback;

HoppingAmplitude up(zeemanCallback, {0, 0, 0}, {0, 0, 0});

HoppingAmplitude down(zeemanCallback, {0, 0, 1}, {0, 0, 1});

zeemanCallback.setJ(1);

Streams::out

<< up.getAmplitude() << "\t"

<< down.getAmplitude() << "\n";

Streams::out << "\n";

zeemanCallback.setJ(2);

Streams::out

<< up.getAmplitude() << "\t"

<< down.getAmplitude() << "\n";

**Output:**

-1

1

-2

2