TBTK Need a break? Support the development by playing Polarity Puzzles
Properties

See more details about the Properties in the API

# Containers of physical Properties

Properties are containers of physical properties that can be calculated from a Model. They store both the data itself and meta-data, such as the energy interval they have been calculated over. Properties can also be used as functions of the arguments for which they have been calculated. This makes them convenient building blocks for applications that extend the capabilities beyond those of the standard Solvers.

This chapter discusses the Properties themselves. For information on how to calculate them, see the PropertyExtractors chapter.

# EnergyResolvedProperties

Many Properties are EnergyResolvedProperties, which means that they contain data over some energy interval. It is possible to get information about the interval as follows.

double lowerBound = energyResolvedProperty.getLowerBound();
double upperBound = energyResolvedProperty.getUpperBound();
unsigned resolution = energyResolvedProperty.getResolution();

Here resolution is the number of points with which the data is resolved between the lowerBound and the upperBound.

# Storage modes

There are three different storage modes for Properties called None, Ranges, and Custom. Here we describe the difference between these modes. We also describe how the mode affects how data can be accessed from the Property.

Independently of the storage mode, the total number of data points contained in the Property can be retrieved using

unsigned int size = property.getSize();

## None

This storage mode is for Properties that have no Indices associated with them. For example, the density of states (DOS) and the EigenValues.

If the Property is a function of energy, it is possible to get the nth element using the notation

property(n);

## Ranges

This storage mode is meant for extracting Properties on a regular grid, e.g., the Density on a quadratic lattice. It can be particularly useful when the Property is to be exported for external postprocessing.

When stored on this format, the data and its ranges can be extracted as follows.

const vector<DataType> &data = property.getData();
vector<int> ranges = property.getRanges();

Here DataType should be replaced by the particular data type of the Property's values.

If the data also is a function of energy, with resolution ENERGY_RESOLUTION, then the layout is such that the data can be accessed as follows.

data[ENERGY_RESOLUTION*(ranges[2]*(ranges[1]*x + y) + z) + n];

If the data instead would be two-dimensional and without energy dependence, the data is accessed as follows.

data[ranges[1]*x + y];

## Custom

This storage format is meant for Properties that have been calculated for arbitrary Indices. If the Property has been calculated for a given Index, say {x, y, z, spin}, it is possible to access the value as follows.

property({x, y, z, spin});

If the Property is energy-dependent, we instead use

property({x, y, z, spin}, n);

where n is an energy index.

### Properties with subindex specifiers

A Property may have been calculated using a specifier in one of the Subindices. Consider for example the Index structure {x, y, z, spin}, and the Density obtained through

Property::Density density = propertyExtractor.calculateDensity({
{5, _a_, _a_, IDX_SUM_ALL}
});

Here the Density is being calculated for all possible coordinates of the form $$(5, y, z)$$. However, the subindex specifier IDX_SUM_ALL ensures the spin Subindex is summed over. The resulting Density retains the original Index structure, including the spin Subindex. To get the value of the Density at a specific point $$(5, y, z)$$, we call the Density with a wildcard in the spin Subindex.

density({5, y, z, _a_});

### Index out-of-bounds access

By default, a Property will generate an error when trying to access a value that is not contained in the Property. However, it is possible to configure the Property such that it instead return some default value (e.g. zero). This can be done as follows.

property.setAllowIndexOutOfBoundsAccess(true);
property.setDefaultValue(defaultValue);

We note that it is recommended to be cautious about turning this feature on. Out-of-bounds access is often a sign that something is wrong, and turning this on can, therefore, mask bugs.

# Examples

See the PropertyExtractors chapter for details about the different ways that Properties can be extracted.

## Density

Assume the Index structure {x, y, orbital, spin}.

Ranges format

Property::Density density = propertyExtractor.calculateDensity(
{ _a_, _a_, IDX_SUM_ALL, IDX_SUM_ALL},
{sizeX, sizeY, numOrbitals, 2}
);
vector<int> ranges = density.getRanges();
const vector<double> &data = density.getData();
double d = data[ranges[1]*x + y];

Custom format

Property::Density density = propertyExtractor.calculateDensity({
{_a_, _a_, IDX_SUM_ALL, IDX_SUM_ALL}
});
double d = density({x, y, _a_, _a_});

See more details about the Density in the API

## DOS

None format

Property::DOS dos = propertyExtractor.calculateDOS();
double lowerBound = dos.getLowerBound();
double upperBound = dos.getUpperBound();
double resolution = dos.getResolution();
double d = dos(n);

Here 0 <= n < resolution.

See more details about the DOS in the API

## EigenValues

None format

unsigned int numEigenValues = eigenValues.getSize();
double e = eigenValues(n);

Here 0 <= n < numEigenValues.

See more details about the EigenValues in the API

## LDOS

Assume the Index structure {x, y, z, spin}.

Ranges format

Property::LDOS ldos = propertyExtractor.calculateLDOS(
{ _a_, _a_, IDX_SUM_ALL, IDX_SUM_ALL},
{sizeX, sizeY, numOrbitals, 2}
);
double lowerBound = ldos.getLowerBound();
double upperBound = ldos.getUpperBound();
double resolution = ldos.getResolution();
vector<int> ranges = ldos.getRanges();
const vector<double> &data = ldos.getData();
double d = data[resolution*(ranges[1]*x + y) + n];

Here 0 <= n < resolution.

Custom format

Property::LDOS ldos = propertyExtractor.calculateLDOS({
{_a_, _a_, IDX_SUM_ALL, IDX_SUM_ALL}
});
double lowerBound = ldos.getLowerBound();
double upperBound = ldos.getUpperBound();
double resolution = ldos.getResolution();
double d = ldos({x, y, _a_, _a_}, n);

Here 0 <= n < resolution.

See more details about the LDOS in the API

## Magnetization

Assume the Index structure {x, y, orbital, spin}.

Ranges format

Property::Magnetization magnetization
= propertyExtractor.calculateMagnetization(
{ _a_, _a_, IDX_SUM_ALL, IDX_SPIN},
{sizeX, sizeY, numOrbitals, 2}
);
vector<int> ranges = magnetiation.getRanges();
const vector<SpinMatrix> &data = magnetization.getData();
SpinMatrix spinMatrix = data[ranges[1]*x + y];

Custom format

Property::Magnetization magnetization
= propertyExtractor.calculateMagnetization({
{_a_, _a_, IDX_SUM_ALL, IDX_SPIN}
});
SpinMatrix spinMatrix = magnetization({x, y, _a_, _a_});

## SpinPolarizedLDOS

Assume the Index structure {x, y, orbital, spin}.

Ranges format

Property::SpinPolarizedLDOS spinPolarizedLDOS
= propertyExtractor.calculateSpinPolarizedLDOS(
{ _a_, _a_, IDX_SUM_ALL, IDX_SPIN},
{sizeX, sizeY, numOrbitals, 2}
);
double lowerBound = spinPolarizedLDOS.getLowerBound();
double upperBound = spinPolarizedLDOS.getUpperBound();
double resolution = spinPolarizedLDOS.getResolution();
vector<int> ranges = spinPolarizedLDOS.getRanges();
const vector<SpinMatrix> &data = spinPolarizedLDOS.getData();
SpinMatrix spinMatrix = data[resolution*(ranges[1]*x + y) + n];

Here 0 <= n < resolution.

Custom format

Property::SpinPolarizedLDOS spinPolarizedLDOS
= propertyExtractor.calculateSpinPolarizedLDOS({
{_a_, _a_, IDX_SUM_ALL, IDX_SPIN}
});
double lowerBound = spinPolarizedLDOS.getLowerBound();
double upperBound = spinPolarizedLDOS.getUpperBound();
double resolution = spinPolarizedLDOS.getResolution();
SpinMatrix spinMatrix = spinPolarizedLDOS({x, y, _a_, _a_}, n);

Here 0 <= n < resolution.

## WaveFunctions

Assume the Index structure {x, y, orbital, spin}.

Custom format
The WaveFunctions are extracted somewhat differently from all other Properties. The second argument to the PropertyExtractor call is a list of the eigenstate indices for which to extract the WaveFunctions. This can also be set to _a_ to extract all states.

Property::WaveFunctions waveFunctions
= propertyExtractor.calculateWaveFunctions(
{{_a_, _a_, _a_, _a_}},
{1, 3, 7}
);
vector<unsigned int> &states = waveFunction.getStates();
complex<double> &w = waveFunctions({x, y, orbital, spin}, n);

where n is one of the numbers contained in states.