PropertyExtractors

In order to allow application developers to focus on relevant physical questions rather than algorithm specific details, and to prevent algorithm specific requirements from spreading to other parts of the code, TBTK encourages the use PropertyExtractors for extracting physical quantities from the Solvers. PropertyExtractors are interfaces to Solvers that largely present themselves uniformly to other parts of the code. What this means is that code that relies on calls to a PropertyExtractor is relatively insensitive to what specific Solver that is being used. The application developer is therefore relatively free to change Solver at any stage in the development process. This is e.g. very useful when it is realized that a particular Solver is not the best one for the task. It is also very useful when setting up complex problems where it can be useful to benchmark results from different Solvers against each other. The later is especially true during the development of new Solvers.

The different PropertyExtractors can, however, not have completely identical interfaces, since some properties are simply not possible to calculate with some Solvers. Some Solvers may also make it possible to calculate very specific things that are not possible to do with any other Solver. The PropertyExtractors are therefore largely uniform interfaces, but not identical. However, for most standard properties there at least exists function calls that allow the properties to compile even if they cannot actually perform the calculation. The program will instead print error messages that make it clear that the particular Solver is not able to calculate the property and ask the developer to switch Solver. In fact, this is achieved through inheritance from a common abstract base class called PropertyExtractor::PropertyExtractor and allows for completely Solver independent code to be written that works with the abstract base class rather than the individual Solver specific PropertyExtractors. The experienced C++ programmer can use this to write truly portable code, while the developer unfamiliar with inheritance and abstract classes do not need to worry about these details.

Each of the Solvers described in the Solver chapter have their own PropertyExtractor called PropertyExtractor::Diagonalizer, PropertyExtractor::BlockDiagonalizer, PropertyExtractor::ArnoldiIterator, and PropertyExtractor::ChebyshevExpander. Using the Solver::Diagonalizer as an example, the corresponding PropertyExtractor is created using

PropertyExtractor::Diagonalizer propertyExtractor(solver);

In addition to the PropertyExtractors, TBTK has a set of Property classes that are returned by the PropertyExtractors and which are more extensively described in the chapter Properties. These Property classes supports a few different storage modes internally which allows for different types of extraction. For example does the system in question often have some concrete structure such as a square lattice. In this case it is useful for properties to preserve knowledge about this structure as it can allow for example two-dimensional plots of the data to be done simply. Other times no such structure exists, or properties are just wanted for a few different points for which there is no unifying structure. These different cases require somewhat different approaches for storing the data in memory, as well as for how to instruct the PropertyExtractors how to extract the data. We here describe how to extract the different properties and the reader can jump to any Property of interest to see how to handle the particular situation. The reader is, however, advised to first read the first section about the density since this establishes most of the basic notation. The reader is also referred to the Properties chapter where more details about the Properties are given.

Before continuing, we note that some Properties have an energy dependence. This means that the quantities needs to be evaluated at a certain number of energy points. The PropertyExtractors extracts such properties within an energy window using some energy resolution and this can be set using

propertyExtractor.setEnergyWindow(

LOWER_BOUND,

UPPER_BOUND,

RESOLUTION

);

Here the two first numbers are real values satisfying LOWER_BOUND < UPPER_BOUND, and RESOLUTION is an integer specifying the number of energy points that the window is divided into.

To demonstrate two different modes for extracting properties we consider a Model with the Index-structure {x, y, z, s} with dimensions SIZE_X, SIZE_Y, SIZE_Z, and two spin species. Next, assume that we are interested in extracting the electron density in the z = 10 plane. We can do this as follows

Property::Density density = propertyExtractor.calculateDensity(

{ IDX_X, IDX_Y, 10, IDX_SUM_ALL},

{SIZE_X, SIZE_Y, SIZE_Z, 2}

);

Here the first curly brace specifies how the different subindices are to be treated by the PropertyExtractor. In this case we specify that the x and y indices are to be considered as a first and second running index. Note that the labels IDX_X and IDX_Y has nothing to do with the fact that the index structure has x and y variables at these positions. The two labels could be interchanged, in which case the y-subindex is going to be considered the first index in the Property. A third specifier IDX_Z is also available and it is important that IDX_Z only is used if IDX_Y is used, and IDX_Y only is used if IDX_X is used. The third subindex in the first bracket specifies that the PropertyExtractor should only extract the density for z=10. Finally, the identifier in the fourth position instructs the PropertyExtractor to sum the contribution from all spins.

The second bracket specifies the range over which the subindices run, assuming that they start at {0, 0, 0, 0}. In this case the third subindex will not actually be used and can in principle be set to any value, for which 1 is another reasonable choice as a reminder that only one value is going to be used. While there currently is no way of changing the lower bound for the range, it is possible to limit the upper bound by for example passing {SIZE_X/2, SIZE_Y, SIZE_Z, 2} as second argument. In this case the density will only be evaluated for the lower half of the x-range.

Now assume that we instead are interested in extracting the density for the z = 10 plane, the points along the line (y,z)=(5,15), and the spin down density on site (x,y,z)=(0,0,0). This can be achieved by passing a list of patterns to the PropertyExtractor as follows

Property::Density density = propertyExtractor.calculateDensity({

{_a_, _a_, 10, IDX_SUM_ALL},

{_a_, 5, 15, IDX_SUM_ALL},

{ 0, 0, 0, 1}

});

First note the two curly brackets on the first and last line which means that the other brackets are passed to the function as a list of brackets rather than as individual arguments. This allows for an arbitrary number of patterns to be passed to the PropertyExtractor. The distinction becomes particularly important to keep in mind when only two patterns are supplied, since forgetting the outer brackets will result in the first mode described above to be executed instead. The symbol _a_ indicates wildcards, meaning that any Index that matches the patter will be included independently of the values in these positions. We note here that while the three underscores are useful for improving readability in application code, it is also possible to use the more descriptive identifier IDX_ALL.

The density of states (DOS) is representative for a third internal storage mode since being a system wide property it has no Index-structure.

Property::DOS dos = propertyExtractor.calculateDOS();

Assuming the index structure {x, y, z, s}, with dimensions SIZE_X, SIZE_Y, SIZE_Z, and two spin species, the LDOS can be extracted for the z = 10 plane as

Property::LDOS ldos = propertyExtractor.calculateLDOS(

{ IDX_X, IDX_Y, 10, IDX_SUM_ALL},

{SIZE_X, SIZE_Y, SIZE_Z, 2}

);

or for the plane z=10, along the line (y,z)=(5,15), and for the down spin on site (x,y,z)=(0,0,0) using

Property::LDOS ldos = propertyExtractor.calculateLDOS({

{_a_, _a_, 10, IDX_SUM_ALL},

{_a_, 5, 15, IDX_SUM_ALL},

{ 0, 0, 0, 1}

});

Assuming the index structure {x, y, z, s}, with dimensions SIZE_X, SIZE_Y, SIZE_Z, and two spin species, the Magnetization can be extracted for the z = 10 plane as

Property::Magnetization magnetization

= propertyExtractor.calculateMagnetization(

{ IDX_X, IDX_Y, 10, IDX_SPIN},

{SIZE_X, SIZE_Y, SIZE_Z, 2}

);

or for the plane z=10, along the line (y,z)=(5,15), and for the site (x,y,z)=(0,0,0) using

Property::Magnetization magnetization

= propertyExtractor.calculateMagnetization({

{_a_, _a_, 10, IDX_SPIN},

{_a_, 5, 15, IDX_SPIN},

{ 0, 0, 0, IDX_SPIN}

});

Note that in order to calculate the Magnetization, it is necessary to specify one and only one spin-subindex using IDX_SPIN.

Assuming the index structure {x, y, z, s}, with dimensions SIZE_X, SIZE_Y, SIZE_Z, and two spin species, the SpinPolarizedLDOS can be extracted for the z = 10 plane as

Property::SpinPolarizedLDOS spinPolarizedLDOS

= propertyExtractor.calculateSpinPolarizedLDOS(

{ IDX_X, IDX_Y, 10, IDX_SPIN},

{SIZE_X, SIZE_Y, SIZE_Z, 2}

);

or for the plane z=10, along the line (y,z)=(5,15), and for the site (x,y,z)=(0,0,0) using

Property::SpinPolarizedLDOS spinPolarizedLDOS

= propertyExtractor.calculateSpinPolarizedLDOS({

{_a_, _a_, 10, IDX_SPIN},

{_a_, 5, 15, IDX_SPIN},

{ 0, 0, 0, IDX_SPIN}

});

Note that in order to calculate the SpinPolarizedLDOS, it is necessary to specify one and only one spin-subindex using IDX_SPIN.

Further Properties such as EigenValues, GreensFunction, SelfEnergy, and WaveFunctions are also available but are not yet documented in this manual. If you are interested in these quantities, do not hesitate to contact krist to get further details or to request a speedy update about one or several of these Properties. ofer .bjor nson @phys ics. uu.se