... | ... | @@ -5,7 +5,7 @@ then describe the public API exposed by the new low-level system format. |
|
|
Finally we will discuss the concrete implementation provided with Kwant, the
|
|
|
`kwant.builder.FiniteSystem`.
|
|
|
|
|
|
## Preliminary
|
|
|
## Preliminaries
|
|
|
|
|
|
### Low-Level Site Families
|
|
|
With the new format we will introduce the concept of a site family to the low
|
... | ... | @@ -78,18 +78,13 @@ the connection set would be `{(0,), (1,), (-1,), (2,), (-2,)}`. For a square |
|
|
lattice with nearest-neighbor hoppings the connection set would be `{(0, 0),
|
|
|
(1, 0), (-1, 0), (0, 1), (0, -1)}`
|
|
|
|
|
|
|
|
|
---------------------
|
|
|
##### Footnotes
|
|
|
|
|
|
[1]: Currently, Symmetries are a uniquely high-level concept in Kwant, and only the action of
|
|
|
the group elements on sites is implemented.
|
|
|
|
|
|
[1]: Currently, Symmetries are a uniquely high-level concept in Kwant, and only
|
|
|
the action of the group elements on sites is implemented.
|
|
|
[2]: This is not a very good name, hopefully a better one will be thought up
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## `System` API
|
|
|
Here we define the low-level system API[3].
|
|
|
|
... | ... | @@ -131,11 +126,27 @@ matrix, or a sparse matrix in COO format. |
|
|
|
|
|
### Discussion
|
|
|
|
|
|
#### More general class of systems
|
|
|
Would it be useful to have a more general class of systems that that only
|
|
|
knows how to "act" on a wavefunction? The same question for the symmetries.
|
|
|
|
|
|
#### Calculating band structure
|
|
|
##### More general class of systems
|
|
|
Might be useful to have a more general class of systems that that only knows
|
|
|
how to "act" on a wavefunction. If one has a system that is very connected (so
|
|
|
that the Hamiltonian has essentially`O(N²)` non-zero elements) so that the
|
|
|
Hamiltonian can barely fit in memory this may be useful. Are there some kind
|
|
|
of iterative algorithms that only require this?
|
|
|
|
|
|
In a similar vein, there should probably be a more general class of symmetries
|
|
|
that only know how to "act". This might often be more efficient than
|
|
|
constructing an explicit representation, e.g. for representations that are
|
|
|
actually `U(1)⊗𝟙ₙ`. They should also probably be able to act `m` times
|
|
|
on a wavefunction.
|
|
|
|
|
|
##### Actual data format
|
|
|
Above we have talked about `sequences` of various things. These could be
|
|
|
implemented as simple arrays, since they contain only simple types
|
|
|
(integers). In addition this would keep the interface closed to the
|
|
|
C low-level interface (see below), and so would make interoperability
|
|
|
easier.
|
|
|
|
|
|
##### Calculating band structure
|
|
|
Formally we need to solve an infinite eigenvalue problem. In practice
|
|
|
we use the symmetry of the system to "fold" the problem into the fundamental
|
|
|
domain. The finite eigenvalue problem to solve is then:
|
... | ... | @@ -144,21 +155,22 @@ domain. The finite eigenvalue problem to solve is then: |
|
|
a nₐ
|
|
|
|
|
|
where the first sum is over the symmetry generators, the second sum is over
|
|
|
the cycle length of the generator. `Uₐ(kₐ)` is the `GL(ℂ, N)` representation
|
|
|
the cycle length of the generator. `Uₐ(kₐ)` is the `U(N)` representation
|
|
|
of one of the symmetry group generators, `-π ≤ kₐ ≤ π` is the associated
|
|
|
momentum, `k̲` is a vector of all the momenta. `Hₐₙ` is the Hamiltonian
|
|
|
matrix linking the fundamental domain to the nth domain in the direction
|
|
|
of the generator `a`. For any reasonable system all the `Hₐₙ` are 0 for `n`
|
|
|
larger than a certain value (usually 1 or 2).
|
|
|
larger than a certain value (usually 1 or 2). `E(k̲)` is the energy
|
|
|
and `u(k̲)` is the wavefunction.
|
|
|
|
|
|
We can see that the low-level format naturally provides the necessary
|
|
|
ingredients to be able to set up such a system.
|
|
|
|
|
|
|
|
|
#### Recursive Greens Function
|
|
|
Write this
|
|
|
##### Recursive Greens Function
|
|
|
Write this.
|
|
|
|
|
|
---------------------
|
|
|
##### Footnotes
|
|
|
|
|
|
[3]: We should probably define everything as arrays straight away to make it
|
|
|
easier to conform to the C system API.
|
|
|
|
... | ... | @@ -206,12 +218,16 @@ set then the Hermitian conjugate of each value is calculated, and this |
|
|
is returned.
|
|
|
|
|
|
### Discussion
|
|
|
Write this
|
|
|
|
|
|
##### Storing the `elements`
|
|
|
It's kind of ugly to have to "check" if a particular sequence of elements
|
|
|
corresponds to onsites or hoppings. A distinction needs to be made because
|
|
|
in Kwant onsite value functions only take a *single* `Site`, whereas
|
|
|
hopping value functions take *two* `Site`s.
|
|
|
|
|
|
---------------------
|
|
|
##### Footnotes
|
|
|
[4]: Or not, see the discussion on implementing RGF
|
|
|
|
|
|
[5]: This is ugly and weird, it should be tweaked. This may require a slight
|
|
|
re-definition of the low-level interface.
|
|
|
|
... | ... | @@ -220,33 +236,64 @@ re-definition of the low-level interface. |
|
|
Here we define the C low-level system API. Systems implemented in C must
|
|
|
conform to this interface. Solvers implemented in C may rely on this interface.
|
|
|
|
|
|
### Rationale
|
|
|
There are two possible reasons why having a C interface to Kwant systems
|
|
|
is important:
|
|
|
|
|
|
+ Someone may wish to implement a system for performance reasons
|
|
|
+ Someone may wish to interface a Kwant system with an external solver
|
|
|
that provides some functionality that is *not* provided by Kwant
|
|
|
(e.g. RGF is not currently implemented in Kwant).
|
|
|
|
|
|
It may be argued that the first reason is not so relevant now that the
|
|
|
low-level format supports vectorized evaluation of the Hamiltonian.
|
|
|
A performance-conscious user who has pinpointed the evaluation of the
|
|
|
Hamiltonian as a bottleneck may just vectorize their value functions.
|
|
|
In this way there is only 1 Python function call for each value
|
|
|
function defined in the system (usually less than 10, say). If the
|
|
|
evaluation is still too slow, the user can re-write their value functions
|
|
|
in Cython or directly in C and wrap with a Python interface.
|
|
|
|
|
|
The second reason is still relevant, however. It is unlikely that
|
|
|
the Kwant package will provide *all* the functionality that users
|
|
|
may want (e.g. DFT). Kwant does, however, have a *very* nice high-level
|
|
|
interface for defining tight-binding models; it is entirely feasible
|
|
|
that someone would want to use Kwant "just" for building their systems.
|
|
|
In this case it is imperative that the `System` be accessible in a
|
|
|
supported way from a low-level language like C, as most external solvers
|
|
|
would be implemented in such a low-level language.
|
|
|
|
|
|
|
|
|
### The Proposed Interface
|
|
|
```C
|
|
|
typedef uint32_t uint_t; // may be any suitably large unsigned integer
|
|
|
typedef double complex complex_t ;
|
|
|
|
|
|
struct Symmetry_t {
|
|
|
struct CSymmetry_t {
|
|
|
|
|
|
uint_t num_directions ;
|
|
|
|
|
|
// get a representation of a group element in GL(ℂ, N)
|
|
|
// get a U(N) representation of a group element
|
|
|
// this representation can be used to act on wavefunctions
|
|
|
// returns a representation as a dense matrix
|
|
|
void (*get_dense_representation)(
|
|
|
const void* symmetry,
|
|
|
const uint_t *group_element,
|
|
|
uint_t N,
|
|
|
complex_t* out) ;
|
|
|
complex_t* out
|
|
|
) ;
|
|
|
|
|
|
// get a representation of a group element in GL(ℂ, N)
|
|
|
// get a U(N) representation of a group element
|
|
|
// this representation can be used to act on wavefunctions
|
|
|
// returns a representation as a sparse COO matrix
|
|
|
void (*get_sparse_representation)(
|
|
|
const void *symmetry,
|
|
|
const uint_t *group_element,
|
|
|
const void *symmetry, // the symmetry structure
|
|
|
const uint_t *group_element, // shape: (num_directions,)
|
|
|
uint_t N,
|
|
|
uint_t *out_row_idx,
|
|
|
uint_t *out_col_idx,
|
|
|
complex_t *out) ;
|
|
|
complex_t *out
|
|
|
) ;
|
|
|
|
|
|
} ;
|
|
|
|
... | ... | @@ -255,7 +302,7 @@ struct CSystem_t { |
|
|
uint_t *site_families ; // shape: (n_site_fams, 2)
|
|
|
uint_t n_site_fams ;
|
|
|
|
|
|
struct Symmetry_t *symmetry ;
|
|
|
struct CSymmetry_t *symmetry ;
|
|
|
uint_t *connection_set ; // shape: (n_sym_els, symmetry->num_directions)
|
|
|
uint_t n_sym_els ;
|
|
|
|
... | ... | @@ -300,7 +347,7 @@ struct CSystem_t { |
|
|
|
|
|
### Discussion
|
|
|
|
|
|
#### Array Format
|
|
|
##### Array Format
|
|
|
Most of the arrays are arrays of some "composite" type and hence are "2D
|
|
|
arrays". Maybe instead we should have a `struct` for each one, e.g.:
|
|
|
```C
|
... | ... | @@ -316,5 +363,17 @@ struct Block_t { |
|
|
uint_t sym_el, fam_to, fam_from, chunk, conj ;
|
|
|
} ;
|
|
|
```
|
|
|
This would be more transparent. The disadvantage is that we would be subject
|
|
|
to padding, unless we define the structure as `packed`. |
|
|
This would be more transparent, and might give us some performance
|
|
|
gain from accessing aligned memory (if we use 32-bit integer
|
|
|
types), although we are certainly not at this level of micro-optimization
|
|
|
yet.
|
|
|
|
|
|
##### Symmetries should have an `act` method
|
|
|
Instead of explicitly constructing the `U(N)` representation we should probably
|
|
|
just be able to "act" with the symmetry.
|
|
|
|
|
|
##### Interfaces with other low-level languages
|
|
|
It might also be nice to provide a proper C++ interface, so that people
|
|
|
interfacing with that language do not have to jump through the hoops of doing
|
|
|
OOP in pure C, and can have a nicer interface to arrays than raw pointers,
|
|
|
which are *so* 1980's. |