From 192daae2636bf54478deb41b58daec973f79bc85 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Thu, 5 Dec 2024 17:42:14 +0000 Subject: [PATCH] build based on 8a8b193 --- dev/.documenter-siteinfo.json | 2 +- dev/advanced/meanfield/index.html | 2 +- dev/advanced/nonspatial/index.html | 2 +- dev/advanced/serializers/index.html | 2 +- dev/advanced/wannier90/index.html | 2 +- dev/api/index.html | 115 ++++++++++++------------- dev/examples/index.html | 2 +- dev/index.html | 2 +- dev/objects.inv | Bin 1779 -> 1788 bytes dev/search_index.js | 2 +- dev/tutorial/bandstructures/index.html | 2 +- dev/tutorial/glossary/index.html | 2 +- dev/tutorial/greenfunctions/index.html | 2 +- dev/tutorial/hamiltonians/index.html | 2 +- dev/tutorial/lattices/index.html | 2 +- dev/tutorial/models/index.html | 2 +- dev/tutorial/observables/index.html | 98 +++++++++------------ dev/tutorial/tutorial/index.html | 2 +- 18 files changed, 115 insertions(+), 128 deletions(-) diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 62cd2480..c468de52 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-28T16:36:29","documenter_version":"1.8.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-05T17:42:08","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/dev/advanced/meanfield/index.html b/dev/advanced/meanfield/index.html index cb0d57b1..62b09197 100644 --- a/dev/advanced/meanfield/index.html +++ b/dev/advanced/meanfield/index.html @@ -81,4 +81,4 @@ 0.15596283661234628 + 0.0im 0.34403716338765444 + 0.0im 0.34403716338765344 + 0.0im - 0.15596283661234572 + 0.0im + 0.15596283661234572 + 0.0im diff --git a/dev/advanced/nonspatial/index.html b/dev/advanced/nonspatial/index.html index f9f7dd19..cf3a3b46 100644 --- a/dev/advanced/nonspatial/index.html +++ b/dev/advanced/nonspatial/index.html @@ -49,4 +49,4 @@ 2.1382+0.0im -1.0+0.0im ⋅ ⋅ -1.0+0.0im 2.3618+0.0im -1.0+0.0im ⋅ ⋅ -1.0+0.0im 2.3618+0.0im -1.0+0.0im - ⋅ ⋅ -1.0+0.0im 2.1382+0.0im

Note the ρ[i] above. This indexes ρ at site i. For a multiorbital hamiltonian, this will be a matrix (the local density matrix on each site i). Here it is just a number, either 0.138197 (sites 1 and 4) or 0.361803 (sites 2 and 3).

Sparse vs dense

The method explained above to build a Hamiltonian using --> supports all the SiteSelector and HopSelector functionality of conventional models. Therefore, although the density matrix computed above is dense, its application to the Hamiltonian is sparse: it only touches the onsite matrix elements in this case.

+ ⋅ ⋅ -1.0+0.0im 2.1382+0.0im

Note the ρ[i] above. This indexes ρ at site i. For a multiorbital hamiltonian, this will be a matrix (the local density matrix on each site i). Here it is just a number, either 0.138197 (sites 1 and 4) or 0.361803 (sites 2 and 3).

Sparse vs dense

The method explained above to build a Hamiltonian using --> supports all the SiteSelector and HopSelector functionality of conventional models. Therefore, although the density matrix computed above is dense, its application to the Hamiltonian is sparse: it only touches the onsite matrix elements in this case.

diff --git a/dev/advanced/serializers/index.html b/dev/advanced/serializers/index.html index fffd6d11..a687135f 100644 --- a/dev/advanced/serializers/index.html +++ b/dev/advanced/serializers/index.html @@ -44,4 +44,4 @@ true julia> @btime deserialize!($as, serialize!($v, $as)); - 149.737 ns (0 allocations: 0 bytes)

It also allows powerful compression into relevant degrees of freedom through appropriate use of encoders/decoders, see the serializer docstring.

Serializers of OrbitalSliceArrays

Serialization of OrbitalSliceArrays is simpler than for AbstractHamiltonians, as there is no need for an intermediate Serializer object. To serialize an m::OrbitalSliceArray simply do v = serialize(m). To deserialize, just do m´ = deserialize(m, v).

+ 149.737 ns (0 allocations: 0 bytes)

It also allows powerful compression into relevant degrees of freedom through appropriate use of encoders/decoders, see the serializer docstring.

Serializers of OrbitalSliceArrays

Serialization of OrbitalSliceArrays is simpler than for AbstractHamiltonians, as there is no need for an intermediate Serializer object. To serialize an m::OrbitalSliceArray simply do v = serialize(m). To deserialize, just do m´ = deserialize(m, v).

diff --git a/dev/advanced/wannier90/index.html b/dev/advanced/wannier90/index.html index 6a5d12b1..feae84e2 100644 --- a/dev/advanced/wannier90/index.html +++ b/dev/advanced/wannier90/index.html @@ -57,4 +57,4 @@ WannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input cells : 151 elements : 7560 - modifiers : 2

An interesting application of modifiers is the addition of an electric field that couples to the full r operator. In an strict tight-binding limit, we would add an electric field E simply as an onsite potential

julia> hE = h |> @onsite!((o, r; E = SA[0,0]) -> o + E'*r);

However, we actually have the full r operator now, which includes non-diagonal matrix elements. We can then incorporate the electric field term E'*r more precisely. We can do so using the --> syntax and the indexing functionality of the r::BarebonesOperator that we obtained from Wannier90

julia> hE = h |> @onsite!((o, i; E = SA[0,0]) --> o + E'*r[i,i]) |> @hopping!((t, i, j; E = SA[0,0]) --> t + E'*r[i,j]);
Closures over non-constant objects

Note that the above creates a closure over r, which is not const. As a result this would incur a small performance and allocation cost when evaluating hE(E=...). We can avoid it e.g. by defining r as a constant, const r = sites(w).

+ modifiers : 2

An interesting application of modifiers is the addition of an electric field that couples to the full r operator. In an strict tight-binding limit, we would add an electric field E simply as an onsite potential

julia> hE = h |> @onsite!((o, r; E = SA[0,0]) -> o + E'*r);

However, we actually have the full r operator now, which includes non-diagonal matrix elements. We can then incorporate the electric field term E'*r more precisely. We can do so using the --> syntax and the indexing functionality of the r::BarebonesOperator that we obtained from Wannier90

julia> hE = h |> @onsite!((o, i; E = SA[0,0]) --> o + E'*r[i,i]) |> @hopping!((t, i, j; E = SA[0,0]) --> t + E'*r[i,j]);
Closures over non-constant objects

Note that the above creates a closure over r, which is not const. As a result this would incur a small performance and allocation cost when evaluating hE(E=...). We can avoid it e.g. by defining r as a constant, const r = sites(w).

diff --git a/dev/api/index.html b/dev/api/index.html index a7d6cbbc..5977ed02 100644 --- a/dev/api/index.html +++ b/dev/api/index.html @@ -1,5 +1,5 @@ -API · Quantica.jl

API

Quantica.EigenSolversModule

EigenSolvers is a Quantica submodule containing support for several pre-defined eigensolver extensions. The alias ES can be used in place of EigenSolvers. Currently supported solvers are

ES.LinearAlgebra(; kw...)       # Uses `eigen(mat; kw...)` from the `LinearAlgebra` package
+API · Quantica.jl

API

Quantica.EigenSolversModule

EigenSolvers is a Quantica submodule containing support for several pre-defined eigensolver extensions. The alias ES can be used in place of EigenSolvers. Currently supported solvers are

ES.LinearAlgebra(; kw...)       # Uses `eigen(mat; kw...)` from the `LinearAlgebra` package
 ES.Arpack(; kw...)              # Uses `eigs(mat; kw...)` from the `Arpack` package (WARNING: Arpack is not thread-safe)
 ES.KrylovKit(params...; kw...)  # Uses `eigsolve(mat, params...; kw...)` from the `KrylovKit` package
 ES.ArnoldiMethod(; kw...)       # Uses `partialschur(mat; kw...)` from the `ArnoldiMethod` package.

To use each of these solvers the corresponding package must be loaded with e.g. using ArnoldiMethod. The exception is the default ES.LinearAlgebra which is a direct Quantica dependency and does not require loading.

Additionally, to compute interior eigenvalues, we can use a shift-invert method around energy ϵ0 (uses LinearMaps and a LinearAlgebra.lu factorization), combined with any solver s from the list above:

ES.ShiftInvert(s, ϵ0)           # Perform a lu-based shift-invert with solver `s`

The ShiftInvert solver extension requires doing using LinearMaps.

Examples

julia> using LinearMaps, ArnoldiMethod  # loads required extensions
@@ -11,7 +11,7 @@
  -0.3819660112501042 + 2.407681231060336e-16im
  -0.6180339887498942 - 2.7336317916863215e-16im
   0.6180339887498937 - 1.7243387890744497e-16im
-  0.3819660112501042 - 1.083582785131051e-16im

See also

`spectrum`, `bands`
source
Quantica.ExternalPresetsModule

ExternalPresets is a Quantica submodule containing utilities to import objects from external applications The alias EP can be used in place of ExternalPresets. Currently supported importers are

EP.wannier90(args...; kw...)

For details on the arguments args and keyword arguments kw see the docstring for the corresponding function.

See also

`LatticePresets`, `RegionPresets`, `HamiltonianPresets`
source
Quantica.GreenSolversModule

GreenSolvers is a Quantica submodule containing several pre-defined Green function solvers. The alias GS can be used in place of GS. Currently supported solvers and their possible keyword arguments are

  • GS.SparseLU() : Direct inversion solver for 0D Hamiltonians using a SparseArrays.lu(hmat) factorization
  • GS.Spectrum(; spectrum_kw...) : Diagonalization solver for 0D Hamiltonians using spectrum(h; spectrum_kw...)
    • spectrum_kw... : keyword arguments passed on to spectrum
    • This solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first. Contact self-energies that depend on parameters are supported.
  • GS.Schur(; boundary = Inf) : Solver for 1D Hamiltonians based on a deflated, generalized Schur factorization
    • boundary : 1D cell index of a boundary cell, or Inf for no boundaries. Equivalent to removing that specific cell from the lattice when computing the Green function.
  • GS.KPM(; order = 100, bandrange = missing, kernel = I) : Kernel polynomial method solver for 0D Hamiltonians
    • order : order of the expansion in Chebyshev polynomials Tₙ(h) of the Hamiltonian h (lowest possible order is n = 0).
    • bandrange : a (min_energy, max_energy)::Tuple interval that encompasses the full band of the Hamiltonian. If missing, it is computed automatically, but using ArnoldiMethod is required first.
    • kernel : generalization that computes momenta as μₙ = Tr[Tₙ(h)*kernel], so that the local density of states (see ldos) becomes the density of the kernel operator.
    • This solver does not allow arbitrary indexing of the resulting g::GreenFunction, only on contacts g[contact_ind::Integer]. If the system has none, we can add a dummy contact using attach(h, nothing; sites...), see attach.
  • GS.Bands(bands_arguments; boundary = missing, bands_kw...): solver based on the integration of bandstructure simplices
    • bands_arguments: positional arguments passed on to bands
    • bands_kw: keyword arguments passed on to bands
    • boundary: either missing (no boundary), or dir => cell_pos (single boundary), where dir::Integer is the Bravais vector normal to the boundary, and cell_pos::Integer the value of cell indices cells[dir] that define the boundary (i.e. cells[dir] <= cell_pos are vaccum)
    • This solver only allows zero or one boundary. WARNING: if a boundary is used, the algorithm may become unstable for very fine band meshes.
source
Quantica.HamiltonianPresetsModule

HamiltonianPresets is a Quantica submodule containing several pre-defined Hamiltonians. The alias HP can be used in place of HamiltonianPresets. Currently supported hamiltonians are

HP.graphene(; kw...)
+  0.3819660112501042 - 1.083582785131051e-16im

See also

`spectrum`, `bands`
source
Quantica.ExternalPresetsModule

ExternalPresets is a Quantica submodule containing utilities to import objects from external applications The alias EP can be used in place of ExternalPresets. Currently supported importers are

EP.wannier90(args...; kw...)

For details on the arguments args and keyword arguments kw see the docstring for the corresponding function.

See also

`LatticePresets`, `RegionPresets`, `HamiltonianPresets`
source
Quantica.GreenSolversModule

GreenSolvers is a Quantica submodule containing several pre-defined Green function solvers. The alias GS can be used in place of GS. Currently supported solvers and their possible keyword arguments are

  • GS.SparseLU() : Direct inversion solver for 0D Hamiltonians using a SparseArrays.lu(hmat) factorization
  • GS.Spectrum(; spectrum_kw...) : Diagonalization solver for 0D Hamiltonians using spectrum(h; spectrum_kw...)
    • spectrum_kw... : keyword arguments passed on to spectrum
    • This solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first. Contact self-energies that depend on parameters are supported.
  • GS.Schur(; boundary = Inf) : Solver for 1D Hamiltonians based on a deflated, generalized Schur factorization
    • boundary : 1D cell index of a boundary cell, or Inf for no boundaries. Equivalent to removing that specific cell from the lattice when computing the Green function.
  • GS.KPM(; order = 100, bandrange = missing, kernel = I) : Kernel polynomial method solver for 0D Hamiltonians
    • order : order of the expansion in Chebyshev polynomials Tₙ(h) of the Hamiltonian h (lowest possible order is n = 0).
    • bandrange : a (min_energy, max_energy)::Tuple interval that encompasses the full band of the Hamiltonian. If missing, it is computed automatically, but using ArnoldiMethod is required first.
    • kernel : generalization that computes momenta as μₙ = Tr[Tₙ(h)*kernel], so that the local density of states (see ldos) becomes the density of the kernel operator.
    • This solver does not allow arbitrary indexing of the resulting g::GreenFunction, only on contacts g[contact_ind::Integer]. If the system has none, we can add a dummy contact using attach(h, nothing; sites...), see attach.
  • GS.Bands(bands_arguments; boundary = missing, bands_kw...): solver based on the integration of bandstructure simplices
    • bands_arguments: positional arguments passed on to bands
    • bands_kw: keyword arguments passed on to bands
    • boundary: either missing (no boundary), or dir => cell_pos (single boundary), where dir::Integer is the Bravais vector normal to the boundary, and cell_pos::Integer the value of cell indices cells[dir] that define the boundary (i.e. cells[dir] <= cell_pos are vaccum)
    • This solver only allows zero or one boundary. WARNING: if a boundary is used, the algorithm may become unstable for very fine band meshes.
source
Quantica.HamiltonianPresetsModule

HamiltonianPresets is a Quantica submodule containing several pre-defined Hamiltonians. The alias HP can be used in place of HamiltonianPresets. Currently supported hamiltonians are

HP.graphene(; kw...)
 HP.twisted_bilayer_graphene(; kw...)

For details on the keyword arguments kw see the corresponding docstring

julia> HamiltonianPresets.twisted_bilayer_graphene(twistindices = (30, 1))
 Hamiltonian{Float64,3,2}: Hamiltonian on a 2D Lattice in 3D space
   Bloch harmonics  : 7
@@ -20,7 +20,7 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 0
   Hoppings         : 315684
-  Coordination     : 28.27696

See also

`LatticePresets`, `RegionPresets`, `ExternalPresets`
source
Quantica.LatticePresetsModule

LatticePresets is a Quantica submodule containing several pre-defined lattices. The alias LP can be used in place of LatticePresets. Currently supported lattices are

LP.linear(; a0 = 1, kw...)      # linear lattice in 1D
+  Coordination     : 28.27696

See also

`LatticePresets`, `RegionPresets`, `ExternalPresets`
source
Quantica.LatticePresetsModule

LatticePresets is a Quantica submodule containing several pre-defined lattices. The alias LP can be used in place of LatticePresets. Currently supported lattices are

LP.linear(; a0 = 1, kw...)      # linear lattice in 1D
 LP.square(; a0 = 1, kw...)      # square lattice in 2D
 LP.triangular(; a0 = 1, kw...)  # triangular lattice in 2D
 LP.honeycomb(; a0 = 1, kw...)   # honeycomb lattice in 2D
@@ -39,7 +39,7 @@
   Bravais vectors : [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0]]
   Sublattices     : 1
     Names         : (:A,)
-    Sites         : (1,) --> 1 total per unit cell

See also

`RegionPresets`, `HamiltonianPresets`, `ExternalPresets`
source
Quantica.RegionPresetsModule

RegionPresets is a Quantica submodule containing several pre-defined regions of type Region{E}, where E is the space dimension. The alias RP can be used in place of RegionPresets. Supported regions are

RP.circle(radius = 10, center = (0, 0))                         # 2D
+    Sites         : (1,) --> 1 total per unit cell

See also

`RegionPresets`, `HamiltonianPresets`, `ExternalPresets`
source
Quantica.PathsModule
Paths

A Quantica submodule that contains representations of different integration paths in the complex-ω plane for integrals of the form ∫f(ω)g(ω)dω, where f(ω) is the Fermi distribution at chemical potential µ and temperature kBT. Available paths are:

Paths.radial(ωscale::Real, ϕ)

A four-segment path from ω = -Inf to ω = Inf. The path first ascends along an arc of angle ϕ (with 0 <= ϕ < π/2) and infinite radius. It then converges along a straight line in the second ω-µ quadrant to the chemical potential origin ω = µ. Finally it performs the mirror-symmetric itinerary in the first ω-µ quadrant, ending on the real axis at ω = Inf. The radial segments are traversed at a rate dictated by ωscale, that should represent some relevant energy scale in the system for optimal convergence of integrals. At zero temperature kBT = 0, the two last segments don't contribute and are elided.

Paths.sawtooth(ωpoints...; slope = 1, imshift = true)

A path connecting all points in the ωpoints collection (should all be real), but departing between each two into the complex plane and back with the given slope, forming a sawtooth path. Note that an extra point µ is added to the collection, where µ is the chemical potential, and the real(ω)>µ segments are elided at zero temperatures. If imshift = true all ωpoints (of type T<:Real) are shifted by sqrt(eps(T)) to avoid the real axis.

Paths.sawtooth(ωmax::Real; kw...)

As above with ωpoints = (-ωmax, ωmax).

Paths.polygon(ωpoints...)

A general polygonal path connecting ωpoints, which can be any collection of real or complex numbers

Paths.polygon(ωfunc::Function)

A ageneral polygonal path connecting ωpoints = ωfunc(µ, kBT; params...). This is useful when the desired integration path depends on the chemical potential µ, temperature kBT or other system parameters params.

See also

`densitymatrix`, `josephson`
source
Quantica.RegionPresetsModule

RegionPresets is a Quantica submodule containing several pre-defined regions of type Region{E}, where E is the space dimension. The alias RP can be used in place of RegionPresets. Supported regions are

RP.circle(radius = 10, center = (0, 0))                         # 2D
 RP.ellipse((rx, ry) = (10, 15), center = (0, 0))                # 2D
 RP.square(side = 10, center = (0, 0))                           # 2D
 RP.rectangle((sx, sy) = (10, 15), center = (0, 0))              # 2D
@@ -50,7 +50,7 @@
 false
 
 julia> RegionPresets.circle(10)(0, 0, 20)
-true

See also

`LatticePresets`, `HamiltonianPresets`, `ExternalPresets`
source
Quantica.zerofieldConstant
    zerofield

An sigleton of type ZeroField that represents a zero-valued field. It has the property that it returns zero no matter how it is indexed (zerofield[inds...] = 0.0 * I), so it is useful as a default value in a non-spatial model involving mean fields. See meanfield for a usage example.

See also

`meanfield`
source
Quantica.BoxIteratorType
BoxIterator(seed::SVector{N,Int}; maxiterations = TOOMANYITERS)

Cartesian iterator iter over SVector{N,Int}s (cells) that starts at seed and grows outwards in the form of a box of increasing sides (not necesarily equal) until it encompasses a certain N-dimensional region. To signal that a cell is in the desired region the user calls acceptcell!(iter, cell).

source
Quantica.OrbitalSliceArrayType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
+true

See also

`LatticePresets`, `HamiltonianPresets`, `ExternalPresets`
source
Quantica.zerofieldConstant
    zerofield

An sigleton of type ZeroField that represents a zero-valued field. It has the property that it returns zero no matter how it is indexed (zerofield[inds...] = 0.0 * I), so it is useful as a default value in a non-spatial model involving mean fields. See meanfield for a usage example.

See also

`meanfield`
source
Quantica.BoxIteratorType
BoxIterator(seed::SVector{N,Int}; maxiterations = TOOMANYITERS)

Cartesian iterator iter over SVector{N,Int}s (cells) that starts at seed and grows outwards in the form of a box of increasing sides (not necesarily equal) until it encompasses a certain N-dimensional region. To signal that a cell is in the desired region the user calls acceptcell!(iter, cell).

source
Quantica.OrbitalSliceArrayType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
 mat[rowsel::SiteSelector, colsel::SiteSelector]

If we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.

sites indexing

mat[sites(cell_index, site_indices)]
 mat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]

If we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.

Note that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.

view(mat, rows::CellSites, cols::Cellsites = rows)

Like the above, but returns a view instead of a copy of the indexed orbital matrix.

Note: diagonal indexing is currently not supported by OrbitalSliceArray.

Examples

julia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;
 
@@ -71,7 +71,7 @@
 julia> mat[sites(SA[1], 1)]
 2×2 Matrix{ComplexF64}:
  -1.93554e-9-0.545545im          0.0-0.0im
-         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Quantica.OrbitalSliceMatrixType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
+         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Quantica.OrbitalSliceMatrixType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
 mat[rowsel::SiteSelector, colsel::SiteSelector]

If we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.

sites indexing

mat[sites(cell_index, site_indices)]
 mat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]

If we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.

Note that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.

view(mat, rows::CellSites, cols::Cellsites = rows)

Like the above, but returns a view instead of a copy of the indexed orbital matrix.

Note: diagonal indexing is currently not supported by OrbitalSliceArray.

Examples

julia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;
 
@@ -92,7 +92,7 @@
 julia> mat[sites(SA[1], 1)]
 2×2 Matrix{ComplexF64}:
  -1.93554e-9-0.545545im          0.0-0.0im
-         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Quantica.OrbitalSliceVectorType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
+         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Quantica.OrbitalSliceVectorType
OrbitalSliceArray <: AbstractArray

A type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.

This is the common output type produced by GreenFunctions and most observables.

Note that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].

siteselector indexing

mat[(; rowsites...), (; colsites...)]
 mat[rowsel::SiteSelector, colsel::SiteSelector]

If we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.

sites indexing

mat[sites(cell_index, site_indices)]
 mat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]

If we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.

Note that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.

view(mat, rows::CellSites, cols::Cellsites = rows)

Like the above, but returns a view instead of a copy of the indexed orbital matrix.

Note: diagonal indexing is currently not supported by OrbitalSliceArray.

Examples

julia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;
 
@@ -113,7 +113,7 @@
 julia> mat[sites(SA[1], 1)]
 2×2 Matrix{ComplexF64}:
  -1.93554e-9-0.545545im          0.0-0.0im
-         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Base.positionFunction
position(b::ExternalPresets.WannierBuilder)

Returns the position operator in the Wannier basis. It is given as a r::BarebonesOperator object, which can be indexed as r[s, s´] to obtain matrix elements ⟨s|R|s´⟩ of the position operator R (a vector). Here s and represent site indices, constructed with sites(cell, inds). To obtain the matrix between cells separated by dn::SVector{L,Int}, do r[dn]. The latter will throw an error if the dn harmonic is not present.

See also

`current`, `sites`
source
Base.reverseFunction
reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})

Build a new lattice or hamiltonian with the orientation of all Bravais vectors and harmonics reversed.

See also

`reverse!`, `transform`
source
Base.reverse!Function
reverse!(lat_or_h::Union{Lattice,AbstractHamiltonian})

In-place version of reverse, inverts all Bravais vectors and harmonics of lat_or_h.

See also

`reverse`, `transform`
source
LinearAlgebra.ishermitianFunction
ishermitian(h::Hamiltonian)

Check whether h is Hermitian. This is not supported for h::ParametricHamiltonian, as the result can depend of the specific values of its parameters.

source
Quantica.ExternalPresets.wannier90Function
ExternalPresets.wannier90(filename::String; kw...)

Import a Wannier90 tight-binding file in the form of a w::EP.WannierBuilder object. It can be used to obtain a Hamiltonian with hamiltonian(w), and the matrix of the position operator with sites(w).

ExternalPresets.wannier90(filename, model::AbstractModel; kw...)

Modify the WannierBuilder after import by adding model to it.

push!(w::EP.WannierBuilder, modifier::AbstractModifier)
+         0.0-0.0im       -1.93554e-9-0.545545im

See also

`siteselector`, `cellindices`, `orbaxes`
source
Base.positionFunction
position(b::ExternalPresets.WannierBuilder)

Returns the position operator in the Wannier basis. It is given as a r::BarebonesOperator object, which can be indexed as r[s, s´] to obtain matrix elements ⟨s|R|s´⟩ of the position operator R (a vector). Here s and represent site indices, constructed with sites(cell, inds). To obtain the matrix between cells separated by dn::SVector{L,Int}, do r[dn]. The latter will throw an error if the dn harmonic is not present.

See also

`current`, `sites`
source
Base.reverseFunction
reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})

Build a new lattice or hamiltonian with the orientation of all Bravais vectors and harmonics reversed.

See also

`reverse!`, `transform`
source
Base.reverse!Function
reverse!(lat_or_h::Union{Lattice,AbstractHamiltonian})

In-place version of reverse, inverts all Bravais vectors and harmonics of lat_or_h.

See also

`reverse`, `transform`
source
LinearAlgebra.ishermitianFunction
ishermitian(h::Hamiltonian)

Check whether h is Hermitian. This is not supported for h::ParametricHamiltonian, as the result can depend of the specific values of its parameters.

source
Quantica.ExternalPresets.wannier90Function
ExternalPresets.wannier90(filename::String; kw...)

Import a Wannier90 tight-binding file in the form of a w::EP.WannierBuilder object. It can be used to obtain a Hamiltonian with hamiltonian(w), and the matrix of the position operator with sites(w).

ExternalPresets.wannier90(filename, model::AbstractModel; kw...)

Modify the WannierBuilder after import by adding model to it.

push!(w::EP.WannierBuilder, modifier::AbstractModifier)
 w |> modifier

Applies a modifier to w.

Keywords

  • htol: skip matrix elements of the Hamiltonian smaller than this (in absolute value). Default: 1e-8
  • rtol: skip non-diagonal matrix elements of the position operator smaller than this (in absolute value). Default: 1e-8
  • dim: dimensionality of the embedding space for the Wannier orbitals, dropping trailing dimensions beyond dim if smaller than 3. Default: 3
  • latdim: dimensionality of the lattice, dropping trailing dimensions beyond latdim if smaller than 3. Should be latdim <= dim. Default: dim
  • type: override the real number type of the imported system. Default: Float64

Examples

julia> w = EP.wannier90("wannier_tb.dat", @onsite((; o) -> o);  htol = 1e-4, rtol = 1e-4, dim = 2, type = Float32)
 WannierBuilder{Float32,2,2} : 2-dimensional Hamiltonian builder from Wannier90 input, with positions of type Float32 in 2D-dimensional space
   cells      : 151
@@ -141,14 +141,14 @@
 julia> r[sites(SA[0,0], 3), sites(SA[1,0],2)]
 2-element SVector{2, ComplexF32} with indices SOneTo(2):
  -0.0016230071f0 - 0.00012927242f0im
-   0.008038711f0 + 0.004102786f0im

See also

`hamiltonian`, `position`
source
Quantica.attachFunction
attach(h::AbstractHamiltonian, args..; sites...)
+   0.008038711f0 + 0.004102786f0im

See also

`hamiltonian`, `position`
source
Quantica.attachFunction
attach(h::AbstractHamiltonian, args..; sites...)
 attach(h::OpenHamiltonian, args...; sites...)

Build an h´::OpenHamiltonian by attaching (adding) a Σ::SelfEnergy to a finite number of sites in h specified by siteselector(; sites...). This also defines a "contact" on said sites that can be referred to (with index i::Integer for the i-th attached contact) when slicing Green functions later. Self-energies are taken into account when building the Green function g(ω) = (ω - h´ - Σ(ω))⁻¹ of the resulting , see greenfunction.

Self-energy forms

The different forms of args yield different types of self-energies Σ. Currently supported forms are:

attach(h, gs::GreenSlice, coupling::AbstractModel; transform = missing, sites...)

Adds a generic self-energy Σ(ω) = V´⋅gs(ω)⋅V on h's sites, where V and are couplings (given by coupling) between said sites and the LatticeSlice in gs (after applying transform to the latter). Allowed forms of gs include both g[bath_sites...] and g[contactind::Integer] where g is any GreenFunction.

attach(h, model::ParametricModel; sites...)

Add self-energy Σᵢⱼ(ω) defined by a model composed of parametric terms (@onsite and @hopping) with ω as first argument, as in e.g. @onsite((ω, r) -> Σᵢᵢ(ω, r)) and @hopping((ω, r, dr) -> Σᵢⱼ(ω, r, dr))

attach(h, nothing; sites...)

Add a nothing contact with a null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to labeling those sites with a contact number, but does not lead to any dressing the Green function. This is useful for some GreenFunction solvers such as GS.KPM (see greenfunction), which need to know the sites of interest beforehand (the contact sites in this case).

attach(h, g1D::GreenFunction; reverse = false, transform = identity, sites...)

Add a self-energy Σ(ω) = h₋₁⋅g1D(ω)[surface]⋅h₁ corresponding to a semi-infinite 1D lead (i.e. with a finite boundary, see greenfunction), where h₁ and h₋₁ are intercell couplings, and g1D is the lead GreenFunction. The g1D(ω) is taken at the suface unitcell, either adjacent to the boundary on its positive side (if reverse = false) or on its negative side (if reverse = true). Note that reverse only flips the direction we extend the lattice to form the lead, but does not flip the unit cell (may use transform for that) or any contacts in the lead. The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the left or right unit cell surface of the lead (i.e. sites coupled to the adjacent unit cells), after applying transform to the latter. If they don't match, use the attach syntax below.

Advanced: If the g1D does not have any self-energies, the produced self-energy is in fact an ExtendedSelfEnergy, which is numerically more stable than a naive implementation of RegularSelfEnergy's, since g1D(ω)[surface] is never actually computed. Conversely, if g1D has self-energies attached, a RegularSelfEnergy is produced.

attach(h, g1D::GreenFunction, coupling::AbstractModel; reverse = false, transform = identity,  sites...)

Add a self-energy Σ(ω) = V´⋅g1D(ω)[surface]⋅V corresponding to a 1D lead (semi-infinite or infinite), but with couplings V and , defined by coupling, between sites and the surface lead unitcell (or the one with index zero if there is no boundary) . See also Advanced note above.

Currying

h |> attach(args...; sites...)

Curried form equivalent to attach(h, args...; sites...).

Examples

julia> # A graphene flake with two out-of-plane cubic-lattice leads
 
 julia> g1D = LP.cubic(names = :C) |> hamiltonian(hopping(1)) |> supercell((0,0,1), region = RP.square(4)) |> greenfunction(GS.Schur(boundary = 0));
 
 julia> coupling = hopping(1, range = 2);
 
-julia> gdisk = HP.graphene(a0 = 1, dim = 3) |> supercell(region = RP.circle(10)) |> attach(g1D, coupling; region = RP.square(4)) |> attach(g1D, coupling; region = RP.square(4), reverse = true) |> greenfunction;

See also

`greenfunction`, `GreenSolvers`
source
Quantica.bandsFunction
bands(h::AbstractHamiltonian, xcolᵢ...; kw...)

Construct a Bandstructure object, which contains in particular a collection of continuously connected Subbands of h, obtained by diagonalizing the matrix h(ϕs; params...) on an M-dimensional mesh of points (x₁, x₂, ..., xₘ), where each xᵢ takes values in the collection xcolᵢ. The mapping between points in the mesh points and values of (ϕs; params...) is defined by keyword mapping (identity by default, see Keywords). Diagonalization is multithreaded and will use all available Julia threads (start session with julia -t N to have N threads).

bands(f::Function, xcolᵢ...; kw...)

Like the above using f(ϕs)::AbstractMatrix in place of h(ϕs; params...), and returning a Vector{<:Subband} instead of a Bandstructure object. This is provided as a lower level driver without the added slicing functionality of a full Bandstructure object, see below.

bands(h::AbstractHamiltonian; kw...)

Equivalent to bands(h::AbstractHamiltonian, xcolᵢ...; kw...) with a default xcolᵢ = subdiv(-π, π, 49).

Keywords

  • solver: eigensolver to use for each diagonalization (see Eigensolvers). Default: ES.LinearAlgebra()
  • mapping: a function of the form (x, y, ...) -> ϕs or (x, y, ...) -> ftuple(ϕs...; params...) that translates points (x, y, ...) in the mesh to Bloch phases ϕs or phase+parameter FrankenTuples ftuple(ϕs...; params...). See also linecuts below. Default: identity
  • transform: function to apply to each eigenvalue after diagonalization. Default: identity
  • degtol::Real: maximum distance between to nearby eigenvalue so that they are classified as degenerate. Default: sqrt(eps)
  • split::Bool: whether to split bands into disconnected subbands. Default: true
  • projectors::Bool: whether to compute interpolating subspaces in each simplex (for use as GreenSolver). Default: true
  • warn::Bool: whether to emit warning when band dislocations are encountered. Default: true
  • showprogress::Bool: whether to show or not a progress bar. Default: true
  • defects: (experimental) a collection of extra points to add to the mesh, typically the location of topological band defects such as Dirac points, so that interpolation avoids creating dislocation defects in the bands. You need to also increase patches to repair the subband dislocations using the added defect vertices. Default: ()
  • patches::Integer: (experimental) if a dislocation is encountered, attempt to patch it by searching for the defect recursively to a given order, or using the provided defects (preferred). Default: 0

Currying

h |> bands(xcolᵢ...; kw...)

Curried form of bands equivalent to bands(h, xcolᵢ...; kw...)

Band linecuts

To do a linecut of a bandstructure along a polygonal path in the L-dimensional Brillouin zone, mapping a set of 1D points xs to a set of nodes, with pts interpolation points in each segment, one can use the following convenient syntax

bands(h, subdiv(xs, pts); mapping = (xs => nodes))

Here nodes can be a collection of SVector{L} or of named Brillouin zone points from the list (,:K, :K´, :M, :X, :Y, :Z). If mapping = nodes, then xs defaults to 0:length(nodes)-1. See also subdiv for its alternative methods.

Indexing and slicing

b[i]

Extract i-th subband from b::Bandstructure. i can also be a Vector, an AbstractRange or any other argument accepted by getindex(subbands::Vector, i)

b[slice::Tuple]

Compute a section of b::Bandstructure with a "plane" defined by slice = (ϕ₁, ϕ₂,..., ϕₗ[, ϵ]), where each ϕᵢ or ϵ can be a real number (representing a fixed momentum or energy) or a : (unconstrained along that dimension). For bands of an L-dimensional lattice, slice will be padded to an L+1-long tuple with : if necessary. The result is a collection of of sliced Subbands.

Examples

julia> phis = range(0, 2pi, length = 50); h = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t));
+julia> gdisk = HP.graphene(a0 = 1, dim = 3) |> supercell(region = RP.circle(10)) |> attach(g1D, coupling; region = RP.square(4)) |> attach(g1D, coupling; region = RP.square(4), reverse = true) |> greenfunction;

See also

`greenfunction`, `GreenSolvers`
source
Quantica.bandsFunction
bands(h::AbstractHamiltonian, xcolᵢ...; kw...)

Construct a Bandstructure object, which contains in particular a collection of continuously connected Subbands of h, obtained by diagonalizing the matrix h(ϕs; params...) on an M-dimensional mesh of points (x₁, x₂, ..., xₘ), where each xᵢ takes values in the collection xcolᵢ. The mapping between points in the mesh points and values of (ϕs; params...) is defined by keyword mapping (identity by default, see Keywords). Diagonalization is multithreaded and will use all available Julia threads (start session with julia -t N to have N threads).

bands(f::Function, xcolᵢ...; kw...)

Like the above using f(ϕs)::AbstractMatrix in place of h(ϕs; params...), and returning a Vector{<:Subband} instead of a Bandstructure object. This is provided as a lower level driver without the added slicing functionality of a full Bandstructure object, see below.

bands(h::AbstractHamiltonian; kw...)

Equivalent to bands(h::AbstractHamiltonian, xcolᵢ...; kw...) with a default xcolᵢ = subdiv(-π, π, 49).

Keywords

  • solver: eigensolver to use for each diagonalization (see Eigensolvers). Default: ES.LinearAlgebra()
  • mapping: a function of the form (x, y, ...) -> ϕs or (x, y, ...) -> ftuple(ϕs...; params...) that translates points (x, y, ...) in the mesh to Bloch phases ϕs or phase+parameter FrankenTuples ftuple(ϕs...; params...). See also linecuts below. Default: identity
  • transform: function to apply to each eigenvalue after diagonalization. Default: identity
  • degtol::Real: maximum distance between to nearby eigenvalue so that they are classified as degenerate. Default: sqrt(eps)
  • split::Bool: whether to split bands into disconnected subbands. Default: true
  • projectors::Bool: whether to compute interpolating subspaces in each simplex (for use as GreenSolver). Default: true
  • warn::Bool: whether to emit warning when band dislocations are encountered. Default: true
  • showprogress::Bool: whether to show or not a progress bar. Default: true
  • defects: (experimental) a collection of extra points to add to the mesh, typically the location of topological band defects such as Dirac points, so that interpolation avoids creating dislocation defects in the bands. You need to also increase patches to repair the subband dislocations using the added defect vertices. Default: ()
  • patches::Integer: (experimental) if a dislocation is encountered, attempt to patch it by searching for the defect recursively to a given order, or using the provided defects (preferred). Default: 0

Currying

h |> bands(xcolᵢ...; kw...)

Curried form of bands equivalent to bands(h, xcolᵢ...; kw...)

Band linecuts

To do a linecut of a bandstructure along a polygonal path in the L-dimensional Brillouin zone, mapping a set of 1D points xs to a set of nodes, with pts interpolation points in each segment, one can use the following convenient syntax

bands(h, subdiv(xs, pts); mapping = (xs => nodes))

Here nodes can be a collection of SVector{L} or of named Brillouin zone points from the list (,:K, :K´, :M, :X, :Y, :Z). If mapping = nodes, then xs defaults to 0:length(nodes)-1. See also subdiv for its alternative methods.

Indexing and slicing

b[i]

Extract i-th subband from b::Bandstructure. i can also be a Vector, an AbstractRange or any other argument accepted by getindex(subbands::Vector, i)

b[slice::Tuple]

Compute a section of b::Bandstructure with a "plane" defined by slice = (ϕ₁, ϕ₂,..., ϕₗ[, ϵ]), where each ϕᵢ or ϵ can be a real number (representing a fixed momentum or energy) or a : (unconstrained along that dimension). For bands of an L-dimensional lattice, slice will be padded to an L+1-long tuple with : if necessary. The result is a collection of of sliced Subbands.

Examples

julia> phis = range(0, 2pi, length = 50); h = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t));
 
 julia> bands(h(t = 1), phis, phis)
 Bandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64
@@ -169,14 +169,14 @@
   Subbands  : 1
   Vertices  : 97
   Edges     : 96
-  Simplices : 96

See also

`spectrum`, `subdiv`
source
Quantica.bravais_matrixFunction
bravais_matrix(lat::Lattice)
 bravais_matrix(h::AbstractHamiltonian)

Return the Bravais matrix of lattice lat or AbstractHamiltonian h, with Bravais vectors as its columns.

Examples

julia> lat = lattice(sublat((0,0)), bravais = ((1.0, 2), (3, 4)));
 
 julia> bravais_matrix(lat)
 2×2 SMatrix{2, 2, Float64, 4} with indices SOneTo(2)×SOneTo(2):
  1.0  3.0
  2.0  4.0
-

See also

`lattice`
source
Quantica.combineFunction
combine(lats::Lattice...)

If all lats have compatible Bravais vectors, combine them into a single lattice. If necessary, sublattice names are renamed to remain unique.

combine(hams::Hamiltonians...; coupling = TighbindingModel())

Combine a collection hams of Hamiltonians into one by combining their corresponding lattices, and optionally by adding a coupling between them, given by the hopping terms in coupling.

Note that the coupling model will be applied to the combined lattice (which may have renamed sublattices to avoid name collissions). However, only hopping terms between different hams blocks will be applied.

Limitations

Currently, combine only works with Lattice{T} AbstractHamiltonians{T} with the same T. Furthermore, if any of the hams is a ParametricHamiltonian or coupling is a ParametricModel, the sublattice names of all hams must be distinct. This ensures that parametric models, which get applied through Modifiers after construction of the ParametricHamiltonian, are not applied to the wrong sublattice, since sublattice names could be renamed by combine if they are not unique. Therefore, be sure to choose unique sublattice names upon construction for all the hams to be combined (see lattice).

Examples

julia> # Building Bernal-stacked bilayer graphene
+

See also

`lattice`
source
Quantica.combineFunction
combine(lats::Lattice...)

If all lats have compatible Bravais vectors, combine them into a single lattice. If necessary, sublattice names are renamed to remain unique.

combine(hams::Hamiltonians...; coupling = TighbindingModel())

Combine a collection hams of Hamiltonians into one by combining their corresponding lattices, and optionally by adding a coupling between them, given by the hopping terms in coupling.

Note that the coupling model will be applied to the combined lattice (which may have renamed sublattices to avoid name collissions). However, only hopping terms between different hams blocks will be applied.

Limitations

Currently, combine only works with Lattice{T} AbstractHamiltonians{T} with the same T. Furthermore, if any of the hams is a ParametricHamiltonian or coupling is a ParametricModel, the sublattice names of all hams must be distinct. This ensures that parametric models, which get applied through Modifiers after construction of the ParametricHamiltonian, are not applied to the wrong sublattice, since sublattice names could be renamed by combine if they are not unique. Therefore, be sure to choose unique sublattice names upon construction for all the hams to be combined (see lattice).

Examples

julia> # Building Bernal-stacked bilayer graphene
 
 julia> hbot = HP.graphene(a0 = 1, dim = 3, names = (:A,:B));
 
@@ -190,7 +190,7 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 0
   Hoppings         : 14
-  Coordination     : 3.5

See also

`hopping`
source
Quantica.conductanceFunction
conductance(gs::GreenSlice; nambu = false)

Given a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object G::Conductance representing the zero-temperature, linear, differential conductance Gᵢⱼ = dIᵢ/dVⱼ between contacts i and j at arbitrary bias ω = eV in units of e^2/h. Gᵢⱼ is given by

  Gᵢⱼ =  e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱ-gʳΓⁱgᵃΓʲ]}         (nambu = false)
+  Coordination     : 3.5

See also

`hopping`
source
Quantica.conductanceFunction
conductance(gs::GreenSlice; nambu = false)

Given a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object G::Conductance representing the zero-temperature, linear, differential conductance Gᵢⱼ = dIᵢ/dVⱼ between contacts i and j at arbitrary bias ω = eV in units of e^2/h. Gᵢⱼ is given by

  Gᵢⱼ =  e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱ-gʳΓⁱgᵃΓʲ]}         (nambu = false)
   Gᵢⱼ =  e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱτₑ-gʳΓⁱτ₃gᵃΓʲτₑ]}   (nambu = true)

Here gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i. For Nambu systems (nambu = true), the matrices τₑ=[I 0; 0 0] and τ₃ = [I 0; 0 -I] ensure that charge reversal in Andreev reflections is properly taken into account. For normal systems (nambu = false), the total current at finite bias and temperatures is given by $Iᵢ = e/h × ∫ dω ∑ⱼ [fᵢ(ω) - fⱼ(ω)] Gᵢⱼ(ω)$, where $fᵢ(ω)$ is the Fermi distribution in lead i.

Keywords

  • nambu : whether to consider the Hamiltonian of the system is written in a Nambu basis, each site containing N electron orbitals followed by N hole orbitals.

Full evaluation

G(ω; params...)

Compute the conductance at the specified contacts.

Examples

julia> # A central system g0 with two 1D leads and transparent contacts
 
 julia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
@@ -203,7 +203,7 @@
   Bias contact     : 1
 
 julia> G(0.2) ≈ 3
-true

See also

`greenfunction`, `ldos`, `current`, `josephson`, `transmission`
source
Quantica.currentFunction
current(h::AbstractHamiltonian; charge = -I, direction = 1)

Build an Operator object that behaves like a ParametricHamiltonian in regards to calls and getindex, but whose matrix elements are hoppings $im*(rⱼ-rᵢ)[direction]*charge*tⱼᵢ$, where tᵢⱼ are the hoppings in h. This operator is equal to $∂h/∂Aᵢ$, where Aᵢ is a gauge field along direction = i.

current(gs::GreenSlice; charge = -I, direction = missing)

Build Js::CurrentDensitySlice, a partially evaluated object representing the equilibrium local current density Jᵢⱼ(ω) at arbitrary energy ω from site j to site i, both taken from a specific lattice slice. The current is computed along a given direction (see Keywords).

current(gω::GreenSolution; charge = -I, direction = missing)

Build Jω::CurrentDensitySolution, as above, but for Jᵢⱼ(ω) at a fixed ω and arbitrary sites i, j. See also greenfunction for details on building a GreenSlice and GreenSolution.

The local current density is defined here as $Jᵢⱼ(ω) = (2/h) rᵢⱼ Re Tr[(Hᵢⱼgⱼᵢ(ω) - gᵢⱼ(ω)Hⱼᵢ) * charge]$, with the integrated local current given by $Jᵢⱼ = ∫ f(ω) Jᵢⱼ(ω) dω$. Here Hᵢⱼ is the hopping from site j at rⱼ to i at rᵢ, rᵢⱼ = rᵢ - rⱼ, charge is the charge of carriers in orbital space (see Keywords), and gᵢⱼ(ω) is the retarded Green function between said sites.

Keywords

  • charge : for multiorbital sites, charge can be a general matrix, which allows to compute arbitrary currents, such as spin currents.
  • direction: as defined above, Jᵢⱼ(ω) is a vector. If direction is missing the norm |Jᵢⱼ(ω)| is returned. If it is an u::Union{SVector,Tuple}, u⋅Jᵢⱼ(ω) is returned. If an n::Integer, Jᵢⱼ(ω)[n] is returned.

Full evaluation

Jω[sites...]
+true

See also

`greenfunction`, `ldos`, `current`, `josephson`, `transmission`
source
Quantica.currentFunction
current(h::AbstractHamiltonian; charge = -I, direction = 1)

Build an Operator object that behaves like a ParametricHamiltonian in regards to calls and getindex, but whose matrix elements are hoppings $im*(rⱼ-rᵢ)[direction]*charge*tⱼᵢ$, where tᵢⱼ are the hoppings in h. This operator is equal to $∂h/∂Aᵢ$, where Aᵢ is a gauge field along direction = i.

current(gs::GreenSlice; charge = -I, direction = missing)

Build Js::CurrentDensitySlice, a partially evaluated object representing the equilibrium local current density Jᵢⱼ(ω) at arbitrary energy ω from site j to site i, both taken from a specific lattice slice. The current is computed along a given direction (see Keywords).

current(gω::GreenSolution; charge = -I, direction = missing)

Build Jω::CurrentDensitySolution, as above, but for Jᵢⱼ(ω) at a fixed ω and arbitrary sites i, j. See also greenfunction for details on building a GreenSlice and GreenSolution.

The local current density is defined here as $Jᵢⱼ(ω) = (2/h) rᵢⱼ Re Tr[(Hᵢⱼgⱼᵢ(ω) - gᵢⱼ(ω)Hⱼᵢ) * charge]$, with the integrated local current given by $Jᵢⱼ = ∫ f(ω) Jᵢⱼ(ω) dω$. Here Hᵢⱼ is the hopping from site j at rⱼ to i at rᵢ, rᵢⱼ = rᵢ - rⱼ, charge is the charge of carriers in orbital space (see Keywords), and gᵢⱼ(ω) is the retarded Green function between said sites.

Keywords

  • charge : for multiorbital sites, charge can be a general matrix, which allows to compute arbitrary currents, such as spin currents.
  • direction: as defined above, Jᵢⱼ(ω) is a vector. If direction is missing the norm |Jᵢⱼ(ω)| is returned. If it is an u::Union{SVector,Tuple}, u⋅Jᵢⱼ(ω) is returned. If an n::Integer, Jᵢⱼ(ω)[n] is returned.

Full evaluation

Jω[sites...]
 Js(ω; params...)

Given a partially evaluated Jω::CurrentDensitySolution or ρs::CurrentDensitySlice, build a sparse matrix Jᵢⱼ(ω) along the specified direction of fully evaluated local current densities.

Note: Evaluating the current density returns a SparseMatrixCSC currently, instead of a OrbitalSliceMatrix, since the latter is designed for dense arrays.

Example

julia> # A semi-infinite 1D lead with a magnetic field `B`
 
 julia> g = LP.square() |> supercell((1,0), region = r->-2<r[2]<2) |> hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> greenfunction(GS.Schur(boundary = 0));
@@ -223,13 +223,12 @@
 3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:
   ⋅           7.77156e-16   ⋅
  7.77156e-16   ⋅           5.55112e-16
-  ⋅           5.55112e-16   ⋅

See also

`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`
source
Quantica.decay_lengthsFunction
Quantica.decay_lengths(g::GreenFunctionSchurLead, µ = 0; reverse = false)
+  ⋅           5.55112e-16   ⋅

See also

`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`
source
Quantica.decay_lengthsFunction
Quantica.decay_lengths(g::GreenFunctionSchurLead, µ = 0; reverse = false)
 Quantica.decay_lengths(h::AbstractHamiltonian1D, µ = 0; reverse = false)

Compute the decay lengths of evanescent modes of a 1D AbstractHamiltonian h or a 1D GreenFunction g using the GS.Schur solver. The modes decaying towards positive direction (relative to the Bravais vector) are used, unless reverse = true.

Examples

julia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));
 
 julia> Quantica.decay_lengths(h(U=2))
 1-element Vector{Float64}:
- 0.28364816427662776

See also:

`Quantica.gaps`
source
Quantica.densitymatrixFunction
densitymatrix(gs::GreenSlice; opts...)

Compute a ρ::DensityMatrix at thermal equilibrium on sites encoded in gs. The actual matrix for given system parameters params, and for a given chemical potential mu and temperature kBT is obtained by calling ρ(mu = 0, kBT = 0; params...). The algorithm used is specialized for the GreenSolver used, if available. In this case, opts are options for said algorithm.

densitymatrix(gs::GreenSlice, (ωmin, ωmax); opts..., quadgk_opts...)
-densitymatrix(gs::GreenSlice, ωpoints; opts..., quadgk_opts...)

As above, but using a generic algorithm that relies on numerical integration along a contour in the complex plane, between points (ωmin, ωmax) (or along a polygonal path connecting ωpoints, a collection of numbers), which should be chosen so as to encompass the full system bandwidth. When the ωpoints are all real, an extra point is added at ω = µ to the integration path, to better integrate the step in the Fermi function. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine. See below for additiona opts.

densitymatrix(gs::GreenSlice, ωmax::Number; opts...)

As above with ωmin = -ωmax.

Full evaluation

ρ(μ = 0, kBT = 0; params...)   # where ρ::DensityMatrix

Evaluate the density matrix at chemical potential μ and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any. The result is given as an OrbitalSliceMatrix, see its docstring for further details.

If the generic integration algorithm is used with complex ωpoints, the following form is also available:

ρ(μ = 0, kBT = 0, override_path = missing; params...)

Here override can be a collection of ωpoints that will replace the original ones provided when defining ρ. Alternatively, it can be a function that will be applied to the original ωpoints. This may be useful when the integration path must depend on params.

Algorithms and keywords

The generic integration algorithm allows for the following opts (see also josephson):

  • omegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.
  • imshift: a small imaginary shift to add to the integration contour if all its vertices ωpoints are real numbers. Default: missing which is equivalent to sqrt(eps) for the relevant number type.
  • slope: if ωpoints are all real numbers (typically encompassing the system's bandwidth), the integration contour is transformed into a triangular sawtooth path these points. Between each pair of points the path increases and then decreases linearly with the given slope. Default: 1.0.
  • post: a function to apply to the result of the integration. Default: identity.
  • callback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand evaluated at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.

The quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.

Currently, the following GreenSolvers implement dedicated densitymatrix algorithms:

  • GS.Schur: based on numerical integration over Bloch phase. Boundaries and non-empty contacts are not currently supported. Assumes Hermitian Hamiltonian. No opts.
  • GS.Spectrum: based on summation occupation-weigthed eigenvectors. No opts.
  • GS.KPM: based on the Chebyshev expansion of the Fermi function. Currently only works for zero temperature and only supports nothing contacts (see attach). No opts.

Example

julia> g = HP.graphene(a0 = 1) |> supercell(region = RP.circle(10)) |> greenfunction(GS.Spectrum());
+ 0.28364816427662776

See also:

`Quantica.gaps`
source
Quantica.densitymatrixFunction
densitymatrix(gs::GreenSlice; opts...)

Compute a ρ::DensityMatrix at thermal equilibrium on sites encoded in gs. The actual matrix for given system parameters params, and for a given chemical potential mu and temperature kBT is obtained by calling ρ(mu = 0, kBT = 0; params...). The algorithm used is specialized for the GreenSolver used, if available. In this case, opts are options for said algorithm.

densitymatrix(gs::GreenSlice, path::AbstractIntegrationPath; opts..., quadgk_opts...)

As above, but using a generic algorithm that relies on numerical integration of the Green function gs(ω) along a contour in the complex-ω plane, defined by the path object. See Paths for available paths. Most integration paths employ the Cauchy theorem, and therefore assume that gs(ω) is fully analytic between the path and the real axis. This may not be true if gs contains user-defined contacts created using attach(model) with general ω-dependent models, but note that Quantica will not check for analyticity. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine.

densitymatrix(gs::GreenSlice, ωscale::Real; kw...)

As above with path = Paths.radial(ωscale, π/4), which computes the density matrix by integrating the Green function from ω = -Inf to ω = Inf along a ϕ = π/4 radial complex path, see Paths for details. Here ωscale should correspond to some typical energy scale in the system, which dictates the speed at which we integrate the radial paths (the integration runtime may depend on ωscale, but not the result).

densitymatrix(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)

As above, but with a path = Paths.sawtooth(ωs), which uses a sawtooth-shaped path touching points ωs on the real axes. Ideally, these values should span the full system bandwidth.

Full evaluation

ρ(μ = 0, kBT = 0; params...)   # where ρ::DensityMatrix

Evaluate the density matrix at chemical potential μ and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any. The result is given as an OrbitalSliceMatrix, see its docstring for further details.

Algorithms and keywords

The generic integration algorithm allows for the following opts (see also josephson):

  • omegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.
  • callback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand evaluated at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.

The quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.

Currently, the following GreenSolvers implement dedicated densitymatrix algorithms:

  • GS.Schur: based on numerical integration over Bloch phase. Boundaries and non-empty contacts are not currently supported. Assumes Hermitian Hamiltonian. No opts.
  • GS.Spectrum: based on summation occupation-weigthed eigenvectors. No opts.
  • GS.KPM: based on the Chebyshev expansion of the Fermi function. Currently only works for zero temperature and only supports nothing contacts (see attach). No opts.

Example

julia> g = HP.graphene(a0 = 1) |> supercell(region = RP.circle(10)) |> greenfunction(GS.Spectrum());
 
 julia> ρ = densitymatrix(g[region = RP.circle(0.5)])
 DensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver
@@ -237,7 +236,7 @@
 julia> ρ()  # with mu = kBT = 0 by default
 2×2 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
        0.5+0.0im  -0.262865+0.0im
- -0.262865+0.0im        0.5+0.0im
source
Quantica.deserializeFunction
deserialize(as::AppliedSerializer, v; params...)

Construct h(; params...), where h = Quantica.parametric_hamiltonian(as) is the AbstractHamiltonian enclosed in as, with the matrix elements enconded in v = serialize(s) restored (i.e. overwritten). See serialize for details.

deserialize(m::OrbitalSliceArray, v)

Reconstruct an OrbitalSliceArray with the same structure as m but with the matrix elements enconded in v. This v is typically the result of a serialize call to a another similar m, but the only requirement is that is has the correct size. If v has the wrong eltype, it will be reintepreted to match the eltype of m.

See also

`serializer`, `serialize`, `serialize!`, `deserialize!`
source
Quantica.deserialize!Function
deserialize!(as::AppliedSerializer, v; params...)

In-place version of deserialize. It returns h´ = Quantica.call!(h; params...) with serialised elements v restored (i.e. overwritten). Here h = Quantica.parent_hamiltonian(s) is the AbstractHamiltonian used to construct as. The resulting h´::Hamiltonian is not an independent copy, but is aliased with h.

Examples

julia> h = HP.graphene() |> supercell(2);
+ -0.262865+0.0im        0.5+0.0im
source
Quantica.deserializeFunction
deserialize(as::AppliedSerializer, v; params...)

Construct h(; params...), where h = Quantica.parametric_hamiltonian(as) is the AbstractHamiltonian enclosed in as, with the matrix elements enconded in v = serialize(s) restored (i.e. overwritten). See serialize for details.

deserialize(m::OrbitalSliceArray, v)

Reconstruct an OrbitalSliceArray with the same structure as m but with the matrix elements enconded in v. This v is typically the result of a serialize call to a another similar m, but the only requirement is that is has the correct size. If v has the wrong eltype, it will be reintepreted to match the eltype of m.

See also

`serializer`, `serialize`, `serialize!`, `deserialize!`
source
Quantica.deserialize!Function
deserialize!(as::AppliedSerializer, v; params...)

In-place version of deserialize. It returns h´ = Quantica.call!(h; params...) with serialised elements v restored (i.e. overwritten). Here h = Quantica.parent_hamiltonian(s) is the AbstractHamiltonian used to construct as. The resulting h´::Hamiltonian is not an independent copy, but is aliased with h.

Examples

julia> h = HP.graphene() |> supercell(2);
 
 julia> s = serializer(h)
 AppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars
@@ -255,7 +254,7 @@
 false
 
 julia> h == deserialize(s, serialize(s))
-true

See also

`serializer`, `serialize`, `serialize!`, `deserialize`
source
Quantica.diagonalFunction
diagonal(i; kernel = missing)

Wrapper over site or orbital indices i (used to index into a g::GreenFunction or g::GreenSolution) that represent purely diagonal entries. Here i can be any index accepted in g[i,i], e.g. i::Integer (contact index), i::Colon (merged contacts), i::SiteSelector (selected sites), etc.

If kernel = Q (a matrix) instead of missing, each diagonal block for multiorbital site i is replaced with Tr(gᵢᵢQ).

For a gω::GreenSolution, gω[diagonal(sel)] = diag(gω[sel, sel]), although where possible the former computation is done more efficiently internally.

diagonal(; kernel = missing, sites...)

Equivalent to diagonal(siteselector(; sites...); kernel)

Keywords

- `kernel`: if missing, all orbitals in the diagonal `g[i, i]` are returned when indexing `g[diagonal(i)]`. Otherwise, `Tr(g[site, site]*kernel)` for each site included in `i` is returned.

Example

julia> g = HP.graphene(orbitals = 2) |> attach(nothing, cells = (0,0)) |> greenfunction();
+true

See also

`serializer`, `serialize`, `serialize!`, `deserialize`
source
Quantica.diagonalFunction
diagonal(i; kernel = missing)

Wrapper over site or orbital indices i (used to index into a g::GreenFunction or g::GreenSolution) that represent purely diagonal entries. Here i can be any index accepted in g[i,i], e.g. i::Integer (contact index), i::Colon (merged contacts), i::SiteSelector (selected sites), etc.

If kernel = Q (a matrix) instead of missing, each diagonal block for multiorbital site i is replaced with Tr(gᵢᵢQ).

For a gω::GreenSolution, gω[diagonal(sel)] = diag(gω[sel, sel]), although where possible the former computation is done more efficiently internally.

diagonal(; kernel = missing, sites...)

Equivalent to diagonal(siteselector(; sites...); kernel)

Keywords

- `kernel`: if missing, all orbitals in the diagonal `g[i, i]` are returned when indexing `g[diagonal(i)]`. Otherwise, `Tr(g[site, site]*kernel)` for each site included in `i` is returned.

Example

julia> g = HP.graphene(orbitals = 2) |> attach(nothing, cells = (0,0)) |> greenfunction();
 
 julia> g(1)[diagonal(:)]                            # g(ω = 1) diagonal on all contact orbitals
 4×4 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:
@@ -267,14 +266,14 @@
 julia> g(1)[diagonal(:, kernel = SA[1 0; 0 -1])]    # σz spin density of the above
 2×2 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:
  5.61885e-12+1.38778e-17im           0.0+0.0im
-         0.0+0.0im          -5.61882e-12+2.77556e-17im

See also

`sitepairs`, `greenfunction`, `ldos`, `densitymatrix`
source
Quantica.energiesFunction
energies(sp::Spectrum)

Returns the energies in sp as a vector of Numbers (not necessarily real). Equivalent to first(sp).

See also

`spectrum`, `bands`
source
Quantica.gapFunction
Quantica.gap(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)

Compute the minimal gap around µ, see Quantica.gaps

See also:

`Quantica.gaps`, `Quantica.decay_lengths`
source
Quantica.gapsFunction
Quantica.gaps(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)

Compute the energy gaps of a 1D Hamiltonian h at chemical potential µ. The result is a Vector{T} of the local minima of the |ϵ(ϕ) - µ|, where ϵ(ϕ) is the energy band closest to µ and ϕ ∈ [-π,π] is the Bloch phase. The atol parameter is the absolute tolerance used to determine the local minima versus ϕ, which are computed using the Schur solver for 1D Hamiltonians. The keywords kw are passed to the ArnoldiMethod partialschur! eigensolver (kw = (; nev = 1) by default).

The LinearMaps and ArnoldiMethod packages must be loaded to enable this functionality.

Examples

julia> using LinearMaps, ArnoldiMethod
+         0.0+0.0im          -5.61882e-12+2.77556e-17im

See also

`sitepairs`, `greenfunction`, `ldos`, `densitymatrix`
source
Quantica.energiesFunction
energies(sp::Spectrum)

Returns the energies in sp as a vector of Numbers (not necessarily real). Equivalent to first(sp).

See also

`spectrum`, `bands`
source
Quantica.gapFunction
Quantica.gap(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)

Compute the minimal gap around µ, see Quantica.gaps

See also:

`Quantica.gaps`, `Quantica.decay_lengths`
source
Quantica.gapsFunction
Quantica.gaps(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)

Compute the energy gaps of a 1D Hamiltonian h at chemical potential µ. The result is a Vector{T} of the local minima of the |ϵ(ϕ) - µ|, where ϵ(ϕ) is the energy band closest to µ and ϕ ∈ [-π,π] is the Bloch phase. The atol parameter is the absolute tolerance used to determine the local minima versus ϕ, which are computed using the Schur solver for 1D Hamiltonians. The keywords kw are passed to the ArnoldiMethod partialschur! eigensolver (kw = (; nev = 1) by default).

The LinearMaps and ArnoldiMethod packages must be loaded to enable this functionality.

Examples

julia> using LinearMaps, ArnoldiMethod
 
 julia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));
 
 julia> Quantica.gaps(h(U=2))
 2-element Vector{Float64}:
  1.9999999999999996
- 1.9999999999999991

See also:

`Quantica.gap`, `Quantica.decay_lengths`
source
Quantica.greenfunctionFunction
greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::AbstractGreenSolver)

Build a g::GreenFunction of Hamiltonian h using solver. See GreenSolvers for available solvers. If solver is not provided, a default solver is chosen automatically based on the type of h.

Currying

h |> greenfunction(solver)

Curried form equivalent to greenfunction(h, solver).

Partial evaluation

GreenFunctions allow independent, partial evaluation of their positions (producing a GreenSlice) and energy/parameters (producing a GreenSolution). Depending on the solver, this may avoid repeating calculations unnecesarily when sweeping over either of these with the other fixed.

g[ss]
+ 1.9999999999999991

See also:

`Quantica.gap`, `Quantica.decay_lengths`
source
Quantica.greenfunctionFunction
greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::AbstractGreenSolver)

Build a g::GreenFunction of Hamiltonian h using solver. See GreenSolvers for available solvers. If solver is not provided, a default solver is chosen automatically based on the type of h.

Currying

h |> greenfunction(solver)

Curried form equivalent to greenfunction(h, solver).

Partial evaluation

GreenFunctions allow independent, partial evaluation of their positions (producing a GreenSlice) and energy/parameters (producing a GreenSolution). Depending on the solver, this may avoid repeating calculations unnecesarily when sweeping over either of these with the other fixed.

g[ss]
 g[siteselector(; ss...)]

Build a gs::GreenSlice that represents a Green function at arbitrary energy and parameter values, but at specific sites on the lattice defined by siteselector(; ss...), with ss::NamedTuple (see siteselector).

g[contact_index::Integer]

Build a GreenSlice equivalent to g[contact_sites...], where contact_sites... correspond to sites in contact number contact_index (must have 1<= contact_index <= number_of_contacts). See attach for details on attaching contacts to a Hamiltonian.

g[:]

Build a GreenSlice over all contacts.

g[dst, src]

Build a gs::GreenSlice between sites specified by src and dst, which can take any of the forms above. Therefore, all the previous single-index slice forms correspond to a diagonal block g[i, i].

g[diagonal(i; kernel = missing)]

Build a diagonal gs::GreenSlice over sites specified by i. If kernel = missing the diagonal entries are g[o, o] for orbitals o in sites encoded in i. If kernel is a matrix, the diagonal elements are tr(g[site, site] * kernel) over each site i. Note that if there are several orbitals per site, g[site, site] may have different sizes (i.e. number of orbitals vs number of sites). Upon evaluating gs(ω), the result is a Diagonal matrix wrapped in an OrbitalSliceMatrix, and spans full unit cells.See also diagonal.

g[sitepairs(; kernel = missing, hops...)]

Like the above but for a selection of site pairs selected by hopselector(; hops...). Upon evaluating gs(ω), the result is a SparseMatrixCSC wrapped in an OrbitalSliceMatrix, and spans full unit cells. See also sitepairs.

g(ω; params...)

Build a gω::GreenSolution that represents a retarded Green function at arbitrary points on the lattice, but at fixed energy ω and system parameter values param. If ω is complex, the retarded or advanced Green function is returned, depending on sign(imag(ω)). If ω is Real, a small, positive imaginary part is automatically added internally to produce the retarded g.

gω[i]
 gω[i, j]
 gs(ω; params...)

For any gω::GreenSolution or gs::GreenSlice, build the Green function matrix fully evaluated at fixed energy, parameters and positions. The matrix is a dense m::OrbitalSliceMatrix with scalar element type, so that any orbital structure on each site is flattened. Note that the resulting m can itself be indexed over collections of sites with m[i, j], where i, j are siteselector(; ss...) or ss::NamedTuple.

view(gω, i::C, j::C == i)

For any gω::GreenSolution and C<:Union{Colon,Integer}, obtain a view (of type SubArray, not OrbitalSliceMatrix) of the corresponding intra or inter-contact propagator gω[i, j] with minimal allocations.

g(; params...)

For any g::Union{GreenFunction,GreenSlice}, produce a new GreenFunction or GreenSlice with all parameters fixed to params (or to their default values if not provided).

Full evaluation

gs(ω; params...)
@@ -306,7 +305,7 @@
 true
 
 julia> summary(gω[ss])
-"14×14 OrbitalSliceMatrix{ComplexF64,Array}"

See also

`GreenSolvers`, `diagonal`, `sitepairs`, `ldos`, `conductance`, `current`, `josephson`
source
Quantica.hamiltonianFunction
hamiltonian(lat::Lattice, model; orbitals = 1)

Create an AbstractHamiltonian (i.e. an Hamiltonian or ParametricHamiltonian) by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building parametric and non-parametric tight-binding models).

hamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)

Create a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided parametric modifiers (see @onsite! and @hopping! for details on defining modifiers).

hamiltonian(h::AbstractHamiltonian, modifier, modifiers...)

Add modifiers to an existing AbstractHamiltonian.

hamiltonian(h::ParametricHamiltonian)

Return the base (non-parametric) Hamiltonian of h, with all modifiers and parametric model terms removed (see @onsite, @hopping, @onsite!, @hopping!).

Keywords

  • orbitals: number of orbitals per sublattice. If an Integer (or a Val{<:Integer} for type-stability), all sublattices will have the same number of orbitals. A collection of values indicates the orbitals on each sublattice.

Currying

lat |> hamiltonian(model[, modifiers...]; kw...)

Curried form of hamiltonian equivalent to hamiltonian(lat, model, modifiers...; kw...).

lat |> model

Alternative and less general curried form equivalent to hamiltonian(lat, model).

h |> modifier

Alternative and less general curried form equivalent to hamiltonian(h, modifier).

Indexing

h[dn::SVector{L,Int}]
+"14×14 OrbitalSliceMatrix{ComplexF64,Array}"

See also

`GreenSolvers`, `diagonal`, `sitepairs`, `ldos`, `conductance`, `current`, `josephson`
source
Quantica.hamiltonianFunction
hamiltonian(lat::Lattice, model; orbitals = 1)

Create an AbstractHamiltonian (i.e. an Hamiltonian or ParametricHamiltonian) by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building parametric and non-parametric tight-binding models).

hamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)

Create a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided parametric modifiers (see @onsite! and @hopping! for details on defining modifiers).

hamiltonian(h::AbstractHamiltonian, modifier, modifiers...)

Add modifiers to an existing AbstractHamiltonian.

hamiltonian(h::ParametricHamiltonian)

Return the base (non-parametric) Hamiltonian of h, with all modifiers and parametric model terms removed (see @onsite, @hopping, @onsite!, @hopping!).

Keywords

  • orbitals: number of orbitals per sublattice. If an Integer (or a Val{<:Integer} for type-stability), all sublattices will have the same number of orbitals. A collection of values indicates the orbitals on each sublattice.

Currying

lat |> hamiltonian(model[, modifiers...]; kw...)

Curried form of hamiltonian equivalent to hamiltonian(lat, model, modifiers...; kw...).

lat |> model

Alternative and less general curried form equivalent to hamiltonian(lat, model).

h |> modifier

Alternative and less general curried form equivalent to hamiltonian(h, modifier).

Indexing

h[dn::SVector{L,Int}]
 h[dn::NTuple{L,Int}]

Return the Bloch harmonic of an h::AbstractHamiltonian in the form of a SparseMatrixCSC with complex scalar eltype. This matrix is "flat", in the sense that it contains matrix elements between individual orbitals, not sites. This distinction is only relevant for multiorbital Hamiltonians. To access the non-flattened matrix use h[unflat(dn)] (see also unflat).

h[()]

Special syntax equivalent to h[(0...)], which access the fundamental Bloch harmonic.

h[i::CellSites, j::CellSites = i]

With i and j of type CellSites and constructed with sites([cell,] indices), return a SparseMatrixCSC block of h between the sites with the corresponding indices and in the given cells. Alternatively, one can also use view(h, i, j = i), which should be non-allocating for AbstractHamiltonians with uniform number of orbitals.

h[srow::SiteSelector, scol::SiteSelector = srow]
 h[kwrow::NamedTuple, kwcol::NamedTuple = kwrow]

Return an OrbitalSliceMatrix of h between row and column sites selected by srow and scol, or by siteselector(; kwrow...) and siteselector(; kwcol...)

Note: CellSites and SiteSelectors can be mixed when indexing, in which case the matrix block will be returned as a SparseMatrixCSC, instead of an OrbitalSliceMatrix.

Call syntax

ph(; params...)

Return a h::Hamiltonian from a ph::ParametricHamiltonian by applying specific values to its parameters params. If ph is a non-parametric Hamiltonian instead, this is a no-op.

h(φs; params...)

Return the flat, sparse Bloch matrix of h::AbstractHamiltonian at Bloch phases φs, with applied parameters params if h is a ParametricHamiltonian. The Bloch matrix is defined as

    H = ∑_dn exp(-im φs⋅dn) H_dn

where H_dn = h[dn] is the dn flat Bloch harmonic of h, and φs[i] = k⋅aᵢ in terms of the wavevector k and the Bravais vectors aᵢ.

Examples

julia> h = hamiltonian(LP.honeycomb(), hopping(SA[0 1; 1 0], range = 1/√3), orbitals = 2)
 Hamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space
@@ -335,7 +334,7 @@
  0.0+0.0im  0.0+0.0im  0.0+0.0im  3.0+0.0im
  0.0+0.0im  0.0+0.0im  3.0+0.0im  0.0+0.0im
  0.0+0.0im  3.0+0.0im  0.0+0.0im  0.0+0.0im
- 3.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im

See also

`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`, `OrbitalSliceMatrix`
source
Quantica.hoppingFunction
hopping(t; hops...)
+ 3.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im

See also

`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`, `OrbitalSliceMatrix`
source
Quantica.hoppingFunction
hopping(t; hops...)
 hopping((r, dr) -> t(r, dr); hops...)

Build a TighbindingModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).

Hops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce an Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.

hopping(m::Union{TighbindingModel,ParametricModel}; hops...)

Convert m into a new model with just hopping terms acting on hops.

Model algebra

Models can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.

Examples

julia> model = hopping((r, dr) -> cis(dot(SA[r[2], -r[1]], dr)); dcells = (0,0)) + onsite(r -> rand())
 TightbindingModel: model with 2 terms
   HoppingTerm{Function}:
@@ -359,7 +358,7 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 8
   Hoppings         : 16
-  Coordination     : 2.0

See also

`onsite`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`, `plusadjoint`
source
Quantica.hopselectorFunction
hopselector(; range = neighbors(1), dcells = missing, sublats = missing, region = missing)

Return a HopSelector object that can be used to select a finite set of hops between sites in a lattice. Hops between two sites at positions r₁ = r - dr/2 and r₂ = r + dr, belonging to unit cells with a cell distance dn::SVector{L,Int} and to a sublattices with names s₁::Symbol and s₂::Symbol will be selected only if

`region(r, dr) && (s₁ => s₂ in sublats) && (dcell in dcells) && (norm(dr) <= range)`

If any of these is missing it will not be used to constraint the selection.

Generalization

While range is usually a Real, and sublats and dcells are usually collections of Pair{Symbol}s and SVectors, respectively, they also admit other possibilities:

sublats = :A                       # Hops from :A to :A
+  Coordination     : 2.0

See also

`onsite`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`, `plusadjoint`
source
Quantica.hopselectorFunction
hopselector(; range = neighbors(1), dcells = missing, sublats = missing, region = missing)

Return a HopSelector object that can be used to select a finite set of hops between sites in a lattice. Hops between two sites at positions r₁ = r - dr/2 and r₂ = r + dr, belonging to unit cells with a cell distance dn::SVector{L,Int} and to a sublattices with names s₁::Symbol and s₂::Symbol will be selected only if

`region(r, dr) && (s₁ => s₂ in sublats) && (dcell in dcells) && (norm(dr) <= range)`

If any of these is missing it will not be used to constraint the selection.

Generalization

While range is usually a Real, and sublats and dcells are usually collections of Pair{Symbol}s and SVectors, respectively, they also admit other possibilities:

sublats = :A                       # Hops from :A to :A
 sublats = :A => :B                 # Hops from :A to :B sublattices, but not from :B to :A
 sublats = (:A => :B,)              # Same as above
 sublats = (:A => :B, :C => :D)     # Hopping from :A to :B or :C to :D
@@ -393,25 +392,25 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 0
   Hoppings         : 18
-  Coordination     : 9.0

See also

`siteselector`, `lattice`, `hopping`, `@hopping`, `@hopping!`
source
Quantica.integrandFunction
Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0)

Return the complex integrand d::JosephsonIntegrand whose integral over frequency yields the Josephson current, J(kBT) = post(∫dω d(ω)), with post = real. To evaluate the d for a given ω and parameters, use d(ω; params...), or call!(d, ω; params...) for its mutating (non-allocating) version.

Quantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0)

Like above for the density matrix ρ(mu, kBT), with d::DensityMatrixIntegrand and post = Quantica.gf_to_rho! that computes -(GF-GF')/(2π*im) in place for a matrix GF.

source
Quantica.josephsonFunction
josephson(gs::GreenSlice, ωpoints; opts..., quadgk_opts...)

For a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a J::Josephson object representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated along a polygonal contour connecting ωpoints (a collection of numbers) in the complex plane. When the ωpoints are all real, an extra point is added at ω = 0 to the integration path, to better integrate the step in the Fermi function.

The result of I_J is given in units of qe/h (q is the dimensionless carrier charge). I_J can be written as $I_J = Re ∫ dω f(ω) j(ω)$, where $j(ω) = (qe/h) × 2Tr[(ΣʳᵢGʳ - GʳΣʳᵢ)τz]$. Here f(ω) is the Fermi function with µ = 0.

josephson(gs::GreenSlice, ωmax::Real; kw...)

As above, but with ωpoints = (-ωmax, ωmax).

Full evaluation

J(kBT = 0, override_path = missing; params...)   # where J::Josephson

Evaluate the current I_J at chemical potemtial µ = 0 and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any.

It's possible to use override_path to override a complex integration path at evaluation time. In this case override_path can be a collection of ωpoints that will replace the original ones provided when defining J. Alternatively, it can be a function that will be applied to the original ωpoints. This may be useful when the integration path must depend on params.

Keywords

The generic integration algorithm allows for the following opts (see also densitymatrix):

  • omegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.
  • phases : collection of superconducting phase biases to apply to the contact, so as to efficiently compute the full current-phase relation [I_J(ϕ) for ϕ in phases]. Note that each phase bias ϕ is applied by a [cis(-ϕ/2)*I 0*I; 0*I cis(ϕ/2)*I] rotation to the self energy, which is almost free. If missing, a single I_J is returned.
  • imshift: a small imaginary shift to add to the integration contour if all its vertices ωpoints are real numbers. Default: missing which is equivalent to sqrt(eps) for the relevant number type.
  • slope: if ωpoints, are all real numbers (typically encompassing the system's bandwidth), the integration contour is transformed into a triangular sawtooth path these points. Between each pair of points the path increases and then decreases linearly with the given slope. Default: 1.0.
  • post: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.
  • callback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.

The quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.

Note on analyticity

A non-zero slope parameter (as is the default) moves the integration path into the upper-half complex-ω plane for increased performance. For this to work it's necessary that the Green function and it's attached self-energies all be analytic in the upper half-plane of complex ω. (Technically things will work also with independent analyticity in the upper-left and upper-right quarter-planes, since the path passes 0 by default). However, no check of analyticity is performed, so it is up to the user to ensure that. If this is not possible, consider using slope = 0, or choosing a set of ωpoints that avoids non-analyticities and cuts.

Examples

julia> glead = LP.square() |> hamiltonian(@onsite((; ω = 0) -> 0.0005 * SA[0 1; 1 0] + im*ω*I) + hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell((1,0), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
+  Coordination     : 9.0

See also

`siteselector`, `lattice`, `hopping`, `@hopping`, `@hopping!`
source
Quantica.integrandFunction
Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0; params...)

Return the complex integrand d::JosephsonIntegrand whose integral over frequency yields the Josephson current, J(kBT; params...) = Re(∫dx d(x; params...)), where ω(x) = Quantica.point(x, d) is a path parametrization over real variable x . To evaluate the d for a given x and parameters, use d(x; params...), or call!(d, x; params...) for its mutating (non-allocating) version.

Quantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0; params...)

Like above for the density matrix ρ, with d::DensityMatrixIntegrand, so that ρ(mu, kBT; params...) = -mat_imag(∫dω d(ω; params...))/π, and mat_imag(GF::Matrix) = (GF - GF')/2im.

source
Quantica.josephsonFunction
josephson(gs::GreenSlice, path::AbstractIntegrationPath; opts..., quadgk_opts...)

For a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a J::Josephson object representing the equilibrium (static) Josephson current I_J flowing into g through contact i. The algorithm relies on the integration of a function of gs(ω) (see below) along a contour in the complex-ω plane defined by path (see Paths for available options). Most integration paths employ the Cauchy theorem, and therefore assume that gs(ω) is fully analytic between the path and the real axis. This may not be true if gs contains user-defined contacts created using attach(model) with general ω-dependent models, but note that Quantica will not check for analyticity. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine.

The result of I_J is given in units of qe/h (q is the dimensionless carrier charge). I_J can be written as $I_J = Re ∫ dω f(ω) j(ω)$, where $j(ω) = (qe/h) × 2Tr[(ΣʳᵢGʳ - GʳΣʳᵢ)τz]$. Here f(ω) is the Fermi function with µ = 0.

josephson(gs::GreenSlice, ωscale::Real; kw...)

As above, but with path = Paths.radial(ωscale, π/4), which computes josephson current by integrating the Green function from ω = -Inf to ω = Inf along a ϕ = π/4 radial complex path, see Paths for details. Here ωscale should be some typical energy scale in the system, like the superconducting gap (the integration time may depend on ωscale, but not the result).

josephson(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)

As above, but with a path = Paths.sawtooth(ωs), which uses a sawtooth-shaped path touching points ωs on the real axes. Ideally, these values should span the full system bandwidth.

Full evaluation

J(kBT = 0; params...)   # where J::Josephson

Evaluate the current I_J at chemical potemtial µ = 0 and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any.

Keywords

The generic integration algorithm allows for the following opts (see also densitymatrix):

  • phases : collection of superconducting phase biases to apply to the contact, so as to efficiently compute the full current-phase relation [I_J(ϕ) for ϕ in phases]. Note that each phase bias ϕ is applied by a [cis(-ϕ/2)*I 0*I; 0*I cis(ϕ/2)*I] rotation to the self energy, which is almost free. If missing, a single I_J is returned.
  • omegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.
  • callback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.

The quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.

Examples

julia> glead = LP.square() |> hamiltonian(@onsite((; ω = 0) -> 0.0005 * SA[0 1; 1 0] + im*ω*I) + hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell((1,0), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
 
 julia> g0 = LP.square() |> hamiltonian(hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell(region = r->-2<r[2]<2 && r[1]≈0) |> attach(glead, reverse = true) |> attach(glead) |> greenfunction;
 
-julia> J = josephson(g0[1], 4; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))
+julia> J = josephson(g0[1], 0.0005; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))
 Josephson: equilibrium Josephson current at a specific contact using solver of type JosephsonIntegratorSolver
 
 julia> J(0.0)
 10-element Vector{Float64}:
- 7.060440509787806e-18
- 0.0008178484258721882
- 0.0016108816082772972
- 0.002355033150366814
- 0.0030277117620820513
- 0.003608482493380227
- 0.004079679643085058
- 0.004426918320990192
- 0.004639358112465513
- 2.2618383948099795e-12

See also

`greenfunction`,`ldos`, `current`, `conductance`, `transmission`
source
Quantica.latticeFunction
lattice(sublats::Sublat...; bravais = (), dim, type, names)
+ 1.0130103834038537e-15
+ 0.0008178802022977883
+ 0.0016109471548779466
+ 0.0023551370133118215
+ 0.0030278625151304614
+ 0.003608696305848759
+ 0.00407998998248311
+ 0.0044274100715435295
+ 0.004640372460465891
+ 5.179773035314182e-12

See also

`greenfunction`,`ldos`, `current`, `conductance`, `transmission`
source
Quantica.latticeFunction
lattice(sublats::Sublat...; bravais = (), dim, type, names)
 lattice(sublats::AbstractVector{<:Sublat}; bravais = (), dim, type, names)

Create a Lattice{T,E,L} from sublattices sublats, where L is the number of Bravais vectors given by bravais, T = type is the AbstractFloat type of spatial site coordinates, and dim = E is the spatial embedding dimension.

lattice(lat::Lattice; bravais = missing, dim = missing, type = missing, names = missing)

Create a new lattice by applying any non-missing keywords to lat.

lattice(x)

Return the parent lattice of object x, of type e.g. LatticeSlice, Hamiltonian, etc.

Keywords

  • bravais: a collection of one or more Bravais vectors of type NTuple{E} or SVector{E}. It can also be an AbstractMatrix of dimension E×L. The default bravais = () corresponds to a bounded lattice with no Bravais vectors.
  • names: a collection of Symbols. Can be used to rename sublats. Any repeated names will be replaced if necessary by :A, :B etc. to ensure that all sublattice names are unique.

Indexing

lat[kw...]
 lat[siteselector(; kw...)]

Indexing into a lattice lat with keywords returns LatticeSlice representing a finite collection of sites selected by siteselector(; kw...). See siteselector for details on possible kw, and sites to obtain site positions.

lat[]

Special case equivalent to lat[cells = (0,...)] that returns a LatticeSlice of the zero-th unitcell.

lat[i::CellSites]

With an i of type CellSites contructed with sites([cell,] indices), return a LatticeSlice of the corresponding sites.

Examples

julia> lat = lattice(sublat((0, 0)), sublat((0, 1)); bravais = (1, 0), type = Float32, dim = 3, names = (:up, :down))
 Lattice{Float32,3,1} : 1D lattice in 3D space
@@ -425,7 +424,7 @@
   Bravais vectors : [[1.0, 0.0]]
   Sublattices     : 2
     Names         : (:A, :B)
-    Sites         : (1, 1) --> 2 total per unit cell

See also

`LatticePresets`, `sublat`, `sites`, `supercell`
source
Quantica.ldosFunction
ldos(gs::GreenSlice; kernel = missing)

Build ρs::LocalSpectralDensitySlice, a partially evaluated object representing the local density of states ρᵢ(ω) at specific sites i but at arbitrary energy ω.

ldos(gω::GreenSolution; kernel = missing)

Build ρω::LocalSpectralDensitySolution, as above, but for ρᵢ(ω) at a fixed ω and arbitrary sites i. See also greenfunction for details on building a GreenSlice and GreenSolution.

The local density of states is defined here as $ρᵢ(ω) = -Tr(gᵢᵢ(ω))/π$, where gᵢᵢ(ω) is the retarded Green function at a given site i.

Keywords

  • kernel : for multiorbital sites, kernel allows to compute a generalized ldos ρᵢ(ω) = -imag(Tr(gᵢᵢ(ω) * kernel))/π, where gᵢᵢ(ω) is the retarded Green function at site i and energy ω. If kernel = missing, the complete, orbital-resolved ldos is returned. Default: missing

Full evaluation

ρω[sites...]
+    Sites         : (1, 1) --> 2 total per unit cell

See also

`LatticePresets`, `sublat`, `sites`, `supercell`
source
Quantica.ldosFunction
ldos(gs::GreenSlice; kernel = missing)

Build ρs::LocalSpectralDensitySlice, a partially evaluated object representing the local density of states ρᵢ(ω) at specific sites i but at arbitrary energy ω.

ldos(gω::GreenSolution; kernel = missing)

Build ρω::LocalSpectralDensitySolution, as above, but for ρᵢ(ω) at a fixed ω and arbitrary sites i. See also greenfunction for details on building a GreenSlice and GreenSolution.

The local density of states is defined here as $ρᵢ(ω) = -Tr(gᵢᵢ(ω))/π$, where gᵢᵢ(ω) is the retarded Green function at a given site i.

Keywords

  • kernel : for multiorbital sites, kernel allows to compute a generalized ldos ρᵢ(ω) = -imag(Tr(gᵢᵢ(ω) * kernel))/π, where gᵢᵢ(ω) is the retarded Green function at site i and energy ω. If kernel = missing, the complete, orbital-resolved ldos is returned. Default: missing

Full evaluation

ρω[sites...]
 ρs(ω; params...)

Given a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build an OrbitalSliceVector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states. See OrbitalSliceVector for further details.

Example

julia> g = HP.graphene(a0 = 1, t0 = 1) |> supercell(region = RP.circle(20)) |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 300, bandrange = (-3.1, 3.1)))
 GreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}
   Solver          : AppliedKPMGreenSolver
@@ -451,7 +450,7 @@
  0.036802204179317045
 
 julia> ldos(g(0.2))[1] == -imag.(diag(g[diagonal(1)](0.2))) ./ π
-true

See also

`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`, `OrbitalSliceVector`
source
Quantica.meanfieldFunction
meanfield(g::GreenFunction, args...; kw...)

Build a M::MeanField object that can be used to compute the Hartree-Fock-Bogoliubov mean field Φ between selected sites interacting through a given charge-charge potential. The density matrix used to build the mean field is obtained with densitymatrix(g[pair_selection], args...; kw...), see densitymatrix for details.

The mean field between site i and j is defined as Φᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ, where

hartreeᵢ = ν * Q * Σ_k v_H(r_i-r_k) * tr(ρ[k,k]*Q)
+true

See also

`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`, `OrbitalSliceVector`
source
Quantica.meanfieldFunction
meanfield(g::GreenFunction, args...; kw...)

Build a M::MeanField object that can be used to compute the Hartree-Fock-Bogoliubov mean field Φ between selected sites interacting through a given charge-charge potential. The density matrix used to build the mean field is obtained with densitymatrix(g[pair_selection], args...; kw...), see densitymatrix for details.

The mean field between site i and j is defined as Φᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ, where

hartreeᵢ = ν * Q * Σ_k v_H(r_i-r_k) * tr(ρ[k,k]*Q)
 fockᵢⱼ  = -v_F(r_i-r_j) * Q * ρ[i,j] * Q

Here Q is the charge operator, v_H and v_F are Hartree and Fock interaction potentials, and ρ is the density matrix evaluated at specific chemical potential and temperature. Also ν = ifelse(nambu, 0.5, 1.0), and v_F(0) = v_H(0) = U, where U is the onsite interaction.

Keywords

  • potential: charge-charge potential to use for both Hartree and Fock. Can be a number or a function of position. Default: 1
  • hartree: charge-charge potential v_H for the Hartree mean field. Can be a number or a function of position. Overrides potential. Default: potential
  • fock: charge-charge potential v_F for the Fock mean field. Can be a number, a function of position or nothing. In the latter case all Fock terms (even onsite) will be dropped. Default: hartree
  • onsite: charge-charge onsite potential. Overrides both Hartree and Fock potentials for onsite interactions. Default: hartree(0)
  • charge: a number (in single-orbital systems) or a matrix (in multi-orbital systems) representing the charge operator on each site. Default: I
  • nambu::Bool: specifies whether the model is defined in Nambu space. In such case, charge should also be in Nambu space, typically SA[1 0; 0 -1] or similar. Default: false
  • namburotation::Bool: if nambu == true and spinful systems, specifies whether the spinor basis is [c↑, c↓, c↓⁺, -c↑⁺] (namburotation = true) or [c↑, c↓, c↑⁺, c↓⁺] (namburotation = false). Default: false
  • selector::NamedTuple: a collection of hopselector directives that defines the pairs of sites (pair_selection above) that interact through the charge-charge potential. Default: (; range = 0) (i.e. onsite)

Any additional keywords kw are passed to the densitymatrix function used to compute the mean field, see above

Evaluation and Indexing

M(µ = 0, kBT = 0; params...)    # where M::MeanField

Build an Φ::CompressedOrbitalMatrix, which is a special form of OrbitalSliceMatrix that can be indexed at pairs of individual sites, e.g. ϕ[sites(2), sites(1)] to return an SMatrix. This type of matrix is less flexible than OrbitalSliceMatrix but is fully static, and can encode symmetries. Its features are implementation details and are bound to change. The returned Φ is just meant to be used in non-spatial models, see Examples below.

Examples

julia> model = hopping(I) - @onsite((i; phi = zerofield) --> phi[i]);  # see zerofield docstring
 
 julia> g = LP.honeycomb() |> hamiltonian(model, orbitals = 2) |> supercell((1,-1)) |> greenfunction;
@@ -480,7 +479,7 @@
 julia> phi1[sites(1), sites(2)] |> Quantica.chopsmall
 2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):
  0.00307712+0.0im         0.0+0.0im
-        0.0+0.0im  0.00307712+0.0im

See also

`zerofield`, `densitymatrix`
source
Quantica.neighborsFunction
neighbors(n::Int)

Create a Neighbors(n) object that represents a hopping range to distances corresponding to the n-th nearest neighbors in a given lattice, irrespective of their sublattice. Neighbors at equal distance do not count towards n.

neighbors(n::Int, lat::Lattice)

Obtain the actual nth-nearest-neighbot distance between sites in lattice lat.

See also

`hopping`
source
Quantica.onsiteFunction
onsite(o; sites...)
+        0.0+0.0im  0.00307712+0.0im

See also

`zerofield`, `densitymatrix`
source
Quantica.neighborsFunction
neighbors(n::Int)

Create a Neighbors(n) object that represents a hopping range to distances corresponding to the n-th nearest neighbors in a given lattice, irrespective of their sublattice. Neighbors at equal distance do not count towards n.

neighbors(n::Int, lat::Lattice)

Obtain the actual nth-nearest-neighbot distance between sites in lattice lat.

See also

`hopping`
source
Quantica.onsiteFunction
onsite(o; sites...)
 onsite(r -> o(r); sites...)

Build a TighbindingModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).

Site positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce a Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.

onsite(m::{TighbindingModel,ParametricModel}; sites...)

Convert m into a new model with just onsite terms acting on sites.

Model algebra

Models can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.

Examples

julia> model = onsite(r -> norm(r) * SA[0 1; 1 0]; sublats = :A) - hopping(I; range = 2)
 TightbindingModel: model with 2 terms
   OnsiteTerm{Function}:
@@ -504,7 +503,7 @@
   Element type     : 2 × 2 blocks (ComplexF64)
   Onsites          : 64
   Hoppings         : 2048
-  Coordination     : 32.0

See also

`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`
source
Quantica.orbaxesFunction
orbaxes(A::OrbitalSliceArray)

Return the orbital axes of A. This is a tuple of OrbitalSliceGrouped objects that can be used e.g. to index another OrbitalSliceArray or to inspect the indices of each site with siteindexdict.

Examples

julia> g = HP.graphene(orbitals = 2) |> supercell((1,-1)) |> greenfunction;
+  Coordination     : 32.0

See also

`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`
source
Quantica.orbaxesFunction
orbaxes(A::OrbitalSliceArray)

Return the orbital axes of A. This is a tuple of OrbitalSliceGrouped objects that can be used e.g. to index another OrbitalSliceArray or to inspect the indices of each site with siteindexdict.

Examples

julia> g = HP.graphene(orbitals = 2) |> supercell((1,-1)) |> greenfunction;
 
 julia> d = ldos(g[cells = SA[0]])(2); summary(d)
 "8-element OrbitalSliceVector{Float64,Array}"
@@ -524,8 +523,7 @@
  CellSites{1,Int64} : 1 site in cell zero
   Sites : 3 │ 5:6
  CellSites{1,Int64} : 1 site in cell zero
-  Sites : 4 │ 7:8

See also

`siteindexdict`
source
Quantica.pathFunction
Quantica.path(O::Josephson, args...)
-Quantica.path(O::DensityMatrix, args...)

Return the vertices of the polygonal integration path used to compute O(args...).

source
Quantica.plusadjointFunction
plusadjoint(t::Model)

Returns a model t + t'. This is a convenience function analogous to the + h.c. notation.

Example

julia> model = hopping(im, sublats = :A => :B) |> plusadjoint
+  Sites : 4 │ 7:8

See also

`siteindexdict`
source
Quantica.plusadjointFunction
plusadjoint(t::Model)

Returns a model t + t'. This is a convenience function analogous to the + h.c. notation.

Example

julia> model = hopping(im, sublats = :A => :B) |> plusadjoint
 TightbindingModel: model with 2 terms
   HoppingTerm{Complex{Bool}}:
     Region            : any
@@ -555,7 +553,8 @@
 julia> h((0,0))
 2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
      ⋅      0.0-3.0im
- 0.0+3.0im      ⋅
source
Quantica.serializeFunction
serialize(as::AppliedSerializer{T}; params...)

Construct a Vector{T} that encodes a selection of matrix elements of h(; params...) where h = Quantica.parent_hamiltonian(as) is the AbstractHamiltonian used to build the AppliedSerializer, see serializer.

serialize(m::OrbitalSliceArray)

Return an Array of the same eltype as m that contains all the stored matrix elements of m. See deserialize for the inverse operation.

serialize(T::Type, m::OrbitalSliceArray)

Reinterpret serialize(m) as a collection with eltype T

See also

`serializer`, `serialize!`, `deserialize`, `deserialize!`
source
Quantica.serialize!Function
serialize!(v, as::AppliedSerializer; params...)

Fill v in-place with the output of serialize(as; params...), see serialize for details.

See also

`serialize`, `serialize!`, `deserialize`, `deserialize!`
source
Quantica.serializerFunction
serializer(T::Type, selectors...; parameter = :stream, encoder = identity, decoder = identity)

Construct a abstract s::Serializer object defines the rules to serialize and deserialize an AbstractHamiltonian, i.e. to translate the matrix elements selected by selectors (SiteSelectors or HopSelectors) into a 1D array of scalars of type T.

serializer(T::Type; kw...)

Equivalent to serializer(T, siteselector(), hopselector(); kw...), i.e. with all onsites and hoppings included in selection.

serializer(T::Type, h::AbstractHamiltonian, selectors...; kw...)

Applies a Serializer object like those above, and applies it to h::AbstractHamiltonian to produce an AppliedSerializer{T,<:AbstractHamiltonian}, that can be used to serialize and deserialize h. See serialize and deserialize for further details.

serializer(h::AbstractHamiltonian{T}, selectors...; kw...)

Equivalent to serializer(Complex{T}, h, selectors...; kw...).

Keywords

  • parameter: the parameter name used to address the serialized vector after transforming an AppliedSerializer into a ParametricHamiltonian, see below. Default: :stream.
  • encoder: a function s -> vec that translates a single matrix element s into an collection vec of scalars of type T. Also supported is encoder = (s->vec, (s,s´)->vec´), which applies the second function to hoppings hᵢⱼ = s and their adjoint hⱼᵢ = s´ to encode both in a single collection vec´ (onsites hᵢᵢ are still encoded using the first single-argument function). This is useful for Hermitian Hamiltonians, where hⱼᵢ can be derived from hᵢⱼ. Default: identity.
  • decoder: the inverse function vec -> s of the encoder. If encoder is a tuple, decoder should also be a tuple of the inverse functions of each encoder function. Default: identity.

Note: for an h::AbstractHamiltonian with a non-uniform number of orbitals, the matrix element passed to the encoder should always be assumed to be a square SMatrix of a fixed size that can fit all sites, padded with zeros if necessary (see "Element type" when displaying it, and the output of h[unflat(dn)]). Likewise, the decoder should return a square SMatrix of the same size, or any other container that can be converted to one. The latter is also important in cases with a uniform orbital number greater than one (non-scalar element type).

The user can check that the encoder and decoder are mutual inverses with Quantica.check(s; params...) where params is any choice of Hamiltonian parameters. This essentially checks that h(; params) == deserialize(s, serialize(s; params...); params...) holds.

Call syntax and ParametricHamiltonians

as(; params...)

Transforms as::AppliedSerializer{T,<:ParametricHamiltonian} into an as´::AppliedSerializer{T,<:Hamiltonian} where the enclosed h is replaced by h´ = h(; params...). The in-place (aliasing) version of the above is Quantica.call!(as; params...). Note that the enclosed AbstractHamiltonians can be retrieved with e.g. Quantica.parent_hamiltonian(as).

hamiltonian(as::AppliedSerializer)

Builds a ph::ParametricHamiltonian by adding as as a parametric modifier (similar to @onsite! or @hopping!) to the h::AbstractHamiltonian enclosed in as. As a result, ph acquires a new parameter of the name given by the parameter keyword specified originally (:stream by default, see above). This parameter takes a serialized stream (e.g. the output of serialize(as)) and replaces the corresponding elements in ph.

h |> s

For s::Serializer and h::AbstractHamiltonian, converts s into an as::AppliedSerializer by applying it to h and then adds as as a parametric modifier to h to produce a ph::ParametricHamiltonian, as above. Note that h |> as with as::AppliedSerializer is not allowed, since as can only be a modifier of its enclosed AbstractHamiltonian.

Examples

julia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);
+ 0.0+3.0im      ⋅
source
Quantica.pointsFunction
Quantica.points(O::Josephson, args...)
+Quantica.points(O::DensityMatrix, args...)

Return the vertices of the integration path used to compute O(args...).

source
Quantica.serializeFunction
serialize(as::AppliedSerializer{T}; params...)

Construct a Vector{T} that encodes a selection of matrix elements of h(; params...) where h = Quantica.parent_hamiltonian(as) is the AbstractHamiltonian used to build the AppliedSerializer, see serializer.

serialize(m::OrbitalSliceArray)

Return an Array of the same eltype as m that contains all the stored matrix elements of m. See deserialize for the inverse operation.

serialize(T::Type, m::OrbitalSliceArray)

Reinterpret serialize(m) as a collection with eltype T

See also

`serializer`, `serialize!`, `deserialize`, `deserialize!`
source
Quantica.serialize!Function
serialize!(v, as::AppliedSerializer; params...)

Fill v in-place with the output of serialize(as; params...), see serialize for details.

See also

`serialize`, `serialize!`, `deserialize`, `deserialize!`
source
Quantica.serializerFunction
serializer(T::Type, selectors...; parameter = :stream, encoder = identity, decoder = identity)

Construct a abstract s::Serializer object defines the rules to serialize and deserialize an AbstractHamiltonian, i.e. to translate the matrix elements selected by selectors (SiteSelectors or HopSelectors) into a 1D array of scalars of type T.

serializer(T::Type; kw...)

Equivalent to serializer(T, siteselector(), hopselector(); kw...), i.e. with all onsites and hoppings included in selection.

serializer(T::Type, h::AbstractHamiltonian, selectors...; kw...)

Applies a Serializer object like those above, and applies it to h::AbstractHamiltonian to produce an AppliedSerializer{T,<:AbstractHamiltonian}, that can be used to serialize and deserialize h. See serialize and deserialize for further details.

serializer(h::AbstractHamiltonian{T}, selectors...; kw...)

Equivalent to serializer(Complex{T}, h, selectors...; kw...).

Keywords

  • parameter: the parameter name used to address the serialized vector after transforming an AppliedSerializer into a ParametricHamiltonian, see below. Default: :stream.
  • encoder: a function s -> vec that translates a single matrix element s into an collection vec of scalars of type T. Also supported is encoder = (s->vec, (s,s´)->vec´), which applies the second function to hoppings hᵢⱼ = s and their adjoint hⱼᵢ = s´ to encode both in a single collection vec´ (onsites hᵢᵢ are still encoded using the first single-argument function). This is useful for Hermitian Hamiltonians, where hⱼᵢ can be derived from hᵢⱼ. Default: identity.
  • decoder: the inverse function vec -> s of the encoder. If encoder is a tuple, decoder should also be a tuple of the inverse functions of each encoder function. Default: identity.

Note: for an h::AbstractHamiltonian with a non-uniform number of orbitals, the matrix element passed to the encoder should always be assumed to be a square SMatrix of a fixed size that can fit all sites, padded with zeros if necessary (see "Element type" when displaying it, and the output of h[unflat(dn)]). Likewise, the decoder should return a square SMatrix of the same size, or any other container that can be converted to one. The latter is also important in cases with a uniform orbital number greater than one (non-scalar element type).

The user can check that the encoder and decoder are mutual inverses with Quantica.check(s; params...) where params is any choice of Hamiltonian parameters. This essentially checks that h(; params) == deserialize(s, serialize(s; params...); params...) holds.

Call syntax and ParametricHamiltonians

as(; params...)

Transforms as::AppliedSerializer{T,<:ParametricHamiltonian} into an as´::AppliedSerializer{T,<:Hamiltonian} where the enclosed h is replaced by h´ = h(; params...). The in-place (aliasing) version of the above is Quantica.call!(as; params...). Note that the enclosed AbstractHamiltonians can be retrieved with e.g. Quantica.parent_hamiltonian(as).

hamiltonian(as::AppliedSerializer)

Builds a ph::ParametricHamiltonian by adding as as a parametric modifier (similar to @onsite! or @hopping!) to the h::AbstractHamiltonian enclosed in as. As a result, ph acquires a new parameter of the name given by the parameter keyword specified originally (:stream by default, see above). This parameter takes a serialized stream (e.g. the output of serialize(as)) and replaces the corresponding elements in ph.

h |> s

For s::Serializer and h::AbstractHamiltonian, converts s into an as::AppliedSerializer by applying it to h and then adds as as a parametric modifier to h to produce a ph::ParametricHamiltonian, as above. Note that h |> as with as::AppliedSerializer is not allowed, since as can only be a modifier of its enclosed AbstractHamiltonian.

Examples

julia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);
 
 julia> as = serializer(Float64, h1; encoder = s -> reim(s), decoder = v -> complex(v[1], v[2]))
 AppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars
@@ -592,16 +591,16 @@
   Parameters       : [:U, :stream]
 
 julia> h3(stream = v, U = 5) == h1(U = 4)  # stream overwrites the U=5 onsite terms
-true

See also

`serialize`, `serialize!`, `deserialize`, `deserialize!`, `siteselector`, `hopselector`
source
Quantica.siteindexdictFunction
siteindexdict(axis::OrbitalSliceGrouped)

Return a dictionary of CellSites representing single sites in an orbital axis of an OrbitalSliceArray, typically obtained with orbaxes. See orbaxes for an example.

See also

`orbaxes`, `OrbitalSliceArray`
source
Quantica.sitepairsFunction
sitepairs(s::HopSelector; kernel = missing)

Create a selection of site pairs s::SparseIndices used to sparsely index into a g::GreenFunction or g::GreenSolution, as g[s]. Of the resulting OrbitalSliceMatrix only the selected pairs of matrix elements will be computed, leaving the rest as zero (sparse matrix). The sparse matrix spans the minimum number of complete unit cells to include all site pairs

If kernel = Q (a matrix instead of missing), each of these site blocks gᵢⱼ will be replaced by Tr(kernel * gᵢⱼ).

sitepairs(; kernel = missing, hops...)

Equivalent to sitepairs(hopselector(; hops...); kernel)

Keywords

- `kernel`: if missing, all orbitals blocks `gᵢⱼ = g[i, j]` between selected sites pairs (i,j) are returned when indexing `g[sitepairs(...)]`. Otherwise, `gᵢⱼ` is replaced by `Tr(gᵢⱼ*kernel)`.

Example

julia> g = HP.graphene(orbitals = 2, a0 = 1) |> attach(nothing, cells = (0,0)) |> greenfunction();
+true

See also

`serialize`, `serialize!`, `deserialize`, `deserialize!`, `siteselector`, `hopselector`
source
Quantica.siteindexdictFunction
siteindexdict(axis::OrbitalSliceGrouped)

Return a dictionary of CellSites representing single sites in an orbital axis of an OrbitalSliceArray, typically obtained with orbaxes. See orbaxes for an example.

See also

`orbaxes`, `OrbitalSliceArray`
source
Quantica.sitepairsFunction
sitepairs(s::HopSelector; kernel = missing)

Create a selection of site pairs s::SparseIndices used to sparsely index into a g::GreenFunction or g::GreenSolution, as g[s]. Of the resulting OrbitalSliceMatrix only the selected pairs of matrix elements will be computed, leaving the rest as zero (sparse matrix). The sparse matrix spans the minimum number of complete unit cells to include all site pairs

If kernel = Q (a matrix instead of missing), each of these site blocks gᵢⱼ will be replaced by Tr(kernel * gᵢⱼ).

sitepairs(; kernel = missing, hops...)

Equivalent to sitepairs(hopselector(; hops...); kernel)

Keywords

- `kernel`: if missing, all orbitals blocks `gᵢⱼ = g[i, j]` between selected sites pairs (i,j) are returned when indexing `g[sitepairs(...)]`. Otherwise, `gᵢⱼ` is replaced by `Tr(gᵢⱼ*kernel)`.

Example

julia> g = HP.graphene(orbitals = 2, a0 = 1) |> attach(nothing, cells = (0,0)) |> greenfunction();
 
 julia> summary(g(1)[sitepairs(range = 1)])     # g(ω=1) site blocks between all sites in zero cell and all other sites at distance 1
 "28×4 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}"
 
 julia> summary(g(1)[sitepairs(range = 1, kernel = SA[1 0; 0 -1])])    # σz spin density of the above
-"14×2 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}"

See also

`diagonal`, `hopselector`, `greenfunction`, `ldos`, `densitymatrix`
source
Quantica.sitesFunction
sites(lat::Lattice[, sublat])

Return a collection of site positions in the unit cell of lattice lat. If a sublat::Symbol or sublat::Int is specified, only sites for the specified sublattice are returned.

sites(ls::LatticeSlice)

Return a collection of positions of a LatticeSlice, generally obtained by indexing a lattice lat[sel...] with some siteselector keywords sel. See also lattice.

Note: the returned collections can be of different types (vectors, generators, views...)

sites(cell_index, site_indices)
+"14×2 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}"

See also

`diagonal`, `hopselector`, `greenfunction`, `ldos`, `densitymatrix`
source
Quantica.sitesFunction
sites(lat::Lattice[, sublat])

Return a collection of site positions in the unit cell of lattice lat. If a sublat::Symbol or sublat::Int is specified, only sites for the specified sublattice are returned.

sites(ls::LatticeSlice)

Return a collection of positions of a LatticeSlice, generally obtained by indexing a lattice lat[sel...] with some siteselector keywords sel. See also lattice.

Note: the returned collections can be of different types (vectors, generators, views...)

sites(cell_index, site_indices)
 sites(site_indices)

Construct a simple selector of sites, of type CellSites, with given site_indices in a given cell at cell_index. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_index should be a collection of L integers, where L is the lattice dimension. If omitted, cell_index defaults to the zero-th cell (0,...).

CellSites produced with sites can be used to index Lattices, AbstractHamiltonians, GreenFunctions, GreenSlices, OrbitalSliceArrays, etc. Note that selecting sites based on cell and site indices requires finding the indices beforehand, which can be done e.g. through plotting the system with qplot. This is lower level and potentially more fragile than using siteselectors, as indices are chosen freely by Quantica in an unspecified way, but it does have a smaller overhead.

Examples

julia> sites(LatticePresets.honeycomb(), :A)
 1-element view(::Vector{SVector{2, Float64}}, 1:1) with eltype SVector{2, Float64}:
- [0.0, -0.2886751345948129]

See also

`lattice`, `siteselector`
source
Quantica.siteselectorFunction
siteselector(; region = missing, sublats = missing, cells = missing)

Return a SiteSelector object that can be used to select a finite set of sites in a lattice. Sites at position r::SVector{E}, belonging to a cell of index n::SVector{L,Int} and to a sublattice with name s::Symbol will be selected only if

`region(r) && s in sublats && n in cells`

Any missing region, sublat or cells will not be used to constraint the selection.

Generalization

While sublats and cells are usually collections of Symbols and SVectors, respectively, they also admit other possibilities:

  • If either cells or sublats are a single cell or sublattice, they will be treated as single-element collections
  • If sublat is a collection of Integers, it will refer to sublattice numbers.
  • If cells is an i::Integer, it will be converted to an SVector{1}
  • If cells is a collection, each element will be converted to an SVector.
  • If cells is a boolean function, n in cells will be the result of cells(n)

Usage

Although the constructor siteselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering sites, which themselves call siteselector internally as needed. Some of these functions are

  • getindex(lat::Lattice; kw...) : return a LatticeSlice with sites specified by kw (also lat[kw...])
  • supercell(lat::Lattice; kw...) : returns a bounded lattice with the sites specified by kw
  • onsite(...; kw...) : onsite model term to be applied to sites specified by kw
  • @onsite!(...; kw...) : onsite modifier to be applied to sites specified by kw

See also

`hopselector`, `lattice`, `supercell`, `onsite`, `@onsite`, `@onsite!`
source
Quantica.spectrumFunction
spectrum(h::AbstractHamiltonian, ϕs; solver = EigenSolvers.LinearAlgebra(), transform = missing, params...)

Compute the Spectrum of the Bloch matrix h(ϕs; params...) using the specified eigensolver, with transform applied to the resulting eigenenergies, if not missing. Eigenpairs are sorted by the real part of their energy. See EigenSolvers for available solvers and their options.

spectrum(h::AbstractHamiltonian; kw...)

For a 0D h, equivalent to spectrum(h, (); kw...)

spectrum(m::AbstractMatrix; solver = EigenSolvers.LinearAlgebra()], transform = missing)

Compute the Spectrum of matrix m using solver and transform.

spectrum(b::Bandstructure, ϕs)

Compute the Spectrum corresponding to slicing the bandstructure b at point ϕs of its base mesh (see bands for details).

Indexing and destructuring

Eigenenergies ϵs::Tuple and eigenstates ψs::Matrix can be extracted from a spectrum sp using any of the following

ϵs, ψs = sp
+ [0.0, -0.2886751345948129]

See also

`lattice`, `siteselector`
source
Quantica.siteselectorFunction
siteselector(; region = missing, sublats = missing, cells = missing)

Return a SiteSelector object that can be used to select a finite set of sites in a lattice. Sites at position r::SVector{E}, belonging to a cell of index n::SVector{L,Int} and to a sublattice with name s::Symbol will be selected only if

`region(r) && s in sublats && n in cells`

Any missing region, sublat or cells will not be used to constraint the selection.

Generalization

While sublats and cells are usually collections of Symbols and SVectors, respectively, they also admit other possibilities:

  • If either cells or sublats are a single cell or sublattice, they will be treated as single-element collections
  • If sublat is a collection of Integers, it will refer to sublattice numbers.
  • If cells is an i::Integer, it will be converted to an SVector{1}
  • If cells is a collection, each element will be converted to an SVector.
  • If cells is a boolean function, n in cells will be the result of cells(n)

Usage

Although the constructor siteselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering sites, which themselves call siteselector internally as needed. Some of these functions are

  • getindex(lat::Lattice; kw...) : return a LatticeSlice with sites specified by kw (also lat[kw...])
  • supercell(lat::Lattice; kw...) : returns a bounded lattice with the sites specified by kw
  • onsite(...; kw...) : onsite model term to be applied to sites specified by kw
  • @onsite!(...; kw...) : onsite modifier to be applied to sites specified by kw

See also

`hopselector`, `lattice`, `supercell`, `onsite`, `@onsite`, `@onsite!`
source
Quantica.spectrumFunction
spectrum(h::AbstractHamiltonian, ϕs; solver = EigenSolvers.LinearAlgebra(), transform = missing, params...)

Compute the Spectrum of the Bloch matrix h(ϕs; params...) using the specified eigensolver, with transform applied to the resulting eigenenergies, if not missing. Eigenpairs are sorted by the real part of their energy. See EigenSolvers for available solvers and their options.

spectrum(h::AbstractHamiltonian; kw...)

For a 0D h, equivalent to spectrum(h, (); kw...)

spectrum(m::AbstractMatrix; solver = EigenSolvers.LinearAlgebra()], transform = missing)

Compute the Spectrum of matrix m using solver and transform.

spectrum(b::Bandstructure, ϕs)

Compute the Spectrum corresponding to slicing the bandstructure b at point ϕs of its base mesh (see bands for details).

Indexing and destructuring

Eigenenergies ϵs::Tuple and eigenstates ψs::Matrix can be extracted from a spectrum sp using any of the following

ϵs, ψs = sp
 ϵs = first(sp)
 ϵs = energies(sp)
 ψs = last(sp)
@@ -614,11 +613,11 @@
 States:
 2×2 Matrix{ComplexF64}:
  -0.707107+0.0im  0.707107+0.0im
-  0.707107+0.0im  0.707107+0.0im

See also

`EigenSolvers`, `bands`
source
Quantica.statesFunction
states(sp::Spectrum)

Returns the eigenstates in sp as columns of a matrix. Equivalent to last(sp).

See also

`spectrum`, `bands`
source
Quantica.subdivFunction
subdiv((x₁, x₂, ..., xₙ), (p₁, p₂, ..., pₙ₋₁))

Build a vector of values between x₁ and xₙ containing all xᵢ such that in each interval [xᵢ, xᵢ₊₁] there are pᵢ equally space values.

subdiv((x₁, x₂, ..., xₙ), p)

Same as above with all pᵢ = p

subdiv(x₁, x₂, p)

Equivalent to subdiv((x₁, x₂), p) == collect(range(x₁, x₂, length = p))

source
Quantica.sublatFunction
sublat(sites...; name::Symbol = :A)
+  0.707107+0.0im  0.707107+0.0im

See also

`EigenSolvers`, `bands`
source
Quantica.statesFunction
states(sp::Spectrum)

Returns the eigenstates in sp as columns of a matrix. Equivalent to last(sp).

See also

`spectrum`, `bands`
source
Quantica.subdivFunction
subdiv((x₁, x₂, ..., xₙ), (p₁, p₂, ..., pₙ₋₁))

Build a vector of values between x₁ and xₙ containing all xᵢ such that in each interval [xᵢ, xᵢ₊₁] there are pᵢ equally space values.

subdiv((x₁, x₂, ..., xₙ), p)

Same as above with all pᵢ = p

subdiv(x₁, x₂, p)

Equivalent to subdiv((x₁, x₂), p) == collect(range(x₁, x₂, length = p))

source
Quantica.sublatFunction
sublat(sites...; name::Symbol = :A)
 sublat(sites::AbstractVector; name::Symbol = :A)

Create a Sublat{E,T} that adds a sublattice, of name name, with sites at positions sites in E dimensional space. Sites positions can be entered as Tuples or SVectors.

Examples

julia> sublat((0.0, 0), (1, 1), (1, -1), name = :A)
 Sublat{2,Float64} : sublattice of Float64-typed sites in 2D space
   Sites    : 3
-  Name     : :A
source
Quantica.supercellFunction
supercell(lat::Lattice{E,L}, v::NTuple{L,Integer}...; seed = missing, kw...)
+  Name     : :A
source
Quantica.supercellFunction
supercell(lat::Lattice{E,L}, v::NTuple{L,Integer}...; seed = missing, kw...)
 supercell(lat::Lattice{E,L}, uc::SMatrix{L,L´,Int}; seed = missing, kw...)

Generate a new Lattice from an L-dimensional lattice lat with a larger unit cell, such that its Bravais vectors are br´= br * uc. Here uc::SMatrix{L,L´,Int} is the integer supercell matrix, with the vectors vs as its columns. If no v are given, the new lattice will have no Bravais vectors (i.e. it will be bounded, with its shape determined by keywords kw...). Likewise, if L´ < L, the resulting lattice will be bounded along L´ - L directions, as dictated by kw....

Only sites selected by siteselector(; kw...) will be included in the supercell (see siteselector for details on the available keywords kw). If no keyword region is given in kw, a single Bravais unit cell perpendicular to the v axes will be selected along the L-L´ bounded directions.

supercell(lattice::Lattice{E,L}, factors::Integer...; seed = missing, kw...)

Call supercell with different scaling along each Bravais vector, so that supercell matrix uc is Diagonal(factors). If a single factor is given, uc = SMatrix{L,L}(factor * I)

supercell(h::Hamiltonian, v...; mincoordination = 0, seed = missing, kw...)

Transform the Lattice of h to have a larger unit cell, while expanding the Hamiltonian accordingly.

Keywords

  • seed::NTuple{L,Integer}: starting cell index to perform search of included sites. By default seed = missing, which makes search start from the zero-th cell.
  • mincoordination::Integer: minimum number of nonzero hopping neighbors required for sites to be included in the supercell. Sites with less coordination will be removed recursively, until all remaining sites satisfy mincoordination.

Currying

lat_or_h |> supercell(v...; kw...)

Curried syntax, equivalent to supercell(lat_or_h, v...; kw...)

Examples

julia> LatticePresets.square() |> supercell((1, 1), region = r -> 0 < r[1] < 5)
 Lattice{Float64,2,1} : 1D lattice in 2D space
   Bravais vectors : [[1.0, 1.0]]
@@ -631,7 +630,7 @@
   Bravais vectors : [[1.5, 2.598076], [-1.5, 2.598076]]
   Sublattices     : 2
     Names         : (:A, :B)
-    Sites         : (9, 9) --> 18 total per unit cell

See also

`supercell`, `siteselector`
source
Quantica.torusFunction
torus(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))

For an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new h´::AbstractHamiltonian on a bounded torus, i.e. with all Bravais vectors eliminated by stitching the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along stitched directions will pick up a Bloch phase exp(-iϕ⋅dn).

If a number of phases ϕᵢ are : instead of numbers, the corresponding Bravais vectors will not be stitched, and the resulting will have a finite lattice dimension .

Currying

h |> torus((ϕ₁, ϕ₂,...))

Currying syntax equivalent to torus(h, (ϕ₁, ϕ₂,...)).

Examples

julia> h2D = HP.graphene(); h1D = torus(h2D, (:, 0.2))
+    Sites         : (9, 9) --> 18 total per unit cell

See also

`supercell`, `siteselector`
source
Quantica.torusFunction
torus(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))

For an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new h´::AbstractHamiltonian on a bounded torus, i.e. with all Bravais vectors eliminated by stitching the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along stitched directions will pick up a Bloch phase exp(-iϕ⋅dn).

If a number of phases ϕᵢ are : instead of numbers, the corresponding Bravais vectors will not be stitched, and the resulting will have a finite lattice dimension .

Currying

h |> torus((ϕ₁, ϕ₂,...))

Currying syntax equivalent to torus(h, (ϕ₁, ϕ₂,...)).

Examples

julia> h2D = HP.graphene(); h1D = torus(h2D, (:, 0.2))
 Hamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space
   Bloch harmonics  : 3
   Harmonic size    : 2 × 2
@@ -642,15 +641,15 @@
   Coordination     : 2.0
 
 julia> h2D((0.3, 0.2)) ≈ h1D(0.3)
-true

See also

`hamiltonian`, `supercell`
source
Quantica.transformFunction
transform(lat_or_h::Union{Lattice,AbstractHamiltonian}, f::Function)

Build a new lattice or hamiltonian transforming each site positions r into f(r).

Currying

x |> transform(f::Function)

Curried version of transform, equivalent to transform(f, x)

Note: Unexported Quantica.transform! is also available for in-place transforms. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.

Examples

julia> LatticePresets.square() |> transform(r -> 3r)
+true

See also

`hamiltonian`, `supercell`
source
Quantica.transformFunction
transform(lat_or_h::Union{Lattice,AbstractHamiltonian}, f::Function)

Build a new lattice or hamiltonian transforming each site positions r into f(r).

Currying

x |> transform(f::Function)

Curried version of transform, equivalent to transform(f, x)

Note: Unexported Quantica.transform! is also available for in-place transforms. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.

Examples

julia> LatticePresets.square() |> transform(r -> 3r)
 Lattice{Float64,2,2} : 2D lattice in 2D space
   Bravais vectors : [[3.0, 0.0], [0.0, 3.0]]
   Sublattices     : 1
     Names         : (:A,)
-    Sites         : (1,) --> 1 total per unit cell

See also

`translate`, `reverse`, `reverse!`
source
Quantica.translateFunction
translate(lat::Lattice, δr)

Build a new lattice translating each site positions from r to r + δr, where δr can be a NTuple or an SVector in embedding space.

Currying

x |> translate(δr)

Curried version of translate, equivalent to translate(x, δr)

Note: Unexported Quantica.translate! is also available for in-place translations. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.

Examples

julia> LatticePresets.square() |> translate((3,3)) |> sites
+    Sites         : (1,) --> 1 total per unit cell

See also

`translate`, `reverse`, `reverse!`
source
Quantica.translateFunction
translate(lat::Lattice, δr)

Build a new lattice translating each site positions from r to r + δr, where δr can be a NTuple or an SVector in embedding space.

Currying

x |> translate(δr)

Curried version of translate, equivalent to translate(x, δr)

Note: Unexported Quantica.translate! is also available for in-place translations. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.

Examples

julia> LatticePresets.square() |> translate((3,3)) |> sites
 1-element Vector{SVector{2, Float64}}:
  [3.0, 3.0]
-

See also

`transform`, `reverse`, `reverse!`
source
Quantica.transmissionFunction
transmission(gs::GreenSlice)

Given a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object T::Transmission representing the normal transmission probability Tᵢⱼ(ω) from contact j to i at energy ω. It can be written as $Tᵢⱼ = Tr{gʳΓⁱgᵃΓʲ}$. Here gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i

Full evaluation

T(ω; params...)

Compute the transmission Tᵢⱼ(ω) at a given ω and for the specified params of g.

Examples

julia> # A central system g0 with two 1D leads and transparent contacts
+

See also

`transform`, `reverse`, `reverse!`
source
Quantica.transmissionFunction
transmission(gs::GreenSlice)

Given a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object T::Transmission representing the normal transmission probability Tᵢⱼ(ω) from contact j to i at energy ω. It can be written as $Tᵢⱼ = Tr{gʳΓⁱgᵃΓʲ}$. Here gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i

Full evaluation

T(ω; params...)

Compute the transmission Tᵢⱼ(ω) at a given ω and for the specified params of g.

Examples

julia> # A central system g0 with two 1D leads and transparent contacts
 
 julia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
 
@@ -665,10 +664,10 @@
 false
 
 julia> T(0.2 + 1e-10im) ≈ 3
-true

See also

`greenfunction`, `conductance`, `ldos`, `current`, `josephson`
source
Quantica.unflatFunction
unflat(dn)

Construct an u::Unflat object wrapping some indices dn. This object is meant to be used to index into a h::AbstractHamiltonian as h[u], which returns an non-flattened version of the Bloch harmonic h[dn]. Each element in the matrix h[u] is an SMatrix block representing onsite or hoppings between whole sites, in contrast to h[dn] where they are scalars representing single orbitals. This is only relevant for multi-orbital Hamiltonians h.

unflat()

Equivalent to unflat(())

Examples

julia> h = HP.graphene(orbitals = 2); h[unflat(0,0)]
+true

See also

`greenfunction`, `conductance`, `ldos`, `current`, `josephson`
source
Quantica.unflatFunction
unflat(dn)

Construct an u::Unflat object wrapping some indices dn. This object is meant to be used to index into a h::AbstractHamiltonian as h[u], which returns an non-flattened version of the Bloch harmonic h[dn]. Each element in the matrix h[u] is an SMatrix block representing onsite or hoppings between whole sites, in contrast to h[dn] where they are scalars representing single orbitals. This is only relevant for multi-orbital Hamiltonians h.

unflat()

Equivalent to unflat(())

Examples

julia> h = HP.graphene(orbitals = 2); h[unflat(0,0)]
 2×2 SparseArrays.SparseMatrixCSC{SMatrix{2, 2, ComplexF64, 4}, Int64} with 2 stored entries:
                      ⋅                       [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]
- [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]                      ⋅
source
Quantica.@hoppingMacro
@hopping((; params...) -> t(; params...); hops...)
+ [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]                      ⋅
source
Quantica.@hoppingMacro
@hopping((; params...) -> t(; params...); hops...)
 @hopping((r, dr; params...) -> t(r; params...); hops...)

Build a ParametricModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).

Hops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of site orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.

The difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.

@hopping((ω; params...) -> Σᵢⱼ(ω; params...); hops...)
 @hopping((ω, r, dr; params...) -> Σᵢⱼ(ω, r, dr; params...); hops...)

Special form of a parametric hopping amplitude meant to model a self-energy (see attach).

@hopping((i, j; params...) --> ...; sites...)
 @hopping((ω, i, j; params...) --> ...; sites...)

The --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.

Model algebra

Parametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.

Examples

julia> model = @hopping((r, dr; t = 1, A = Returns(SA[0,0])) -> t * cis(-dr' * A(r)))
@@ -692,7 +691,7 @@
   Onsites          : 0
   Hoppings         : 24
   Coordination     : 3.0
-  Parameters       : [:A, :t]

See also

`onsite`, `hopping`, `@onsite`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@hopping!Macro
@hopping!((t; params...) -> t´(t; params...); hops...)
+  Parameters       : [:A, :t]

See also

`onsite`, `hopping`, `@onsite`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@hopping!Macro
@hopping!((t; params...) -> t´(t; params...); hops...)
 @hopping!((t, r, dr; params...) -> t´(t, r, dr; params...); hops...)

Build a uniform or position-dependent hopping term modifier, respectively, acting on hops selected by hopselector(; hops...) (see hopselector for details).

Hops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. The original hopping amplitude is t, and the modified hopping is , which is a function of t and possibly r, dr. It may optionally also depend on parameters, enconded in params.

Modifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.

@hopping!((t, i, j; params...) --> ...; sites...)

The --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.

Examples

julia> model = hopping(1); peierls = @hopping!((t, r, dr; A = r -> SA[0,0]) -> t * cis(-dr' * A(r)))
 HoppingModifier{ParametricFunction{3}}:
   Region            : any
@@ -712,7 +711,7 @@
   Onsites          : 0
   Hoppings         : 600
   Coordination     : 3.0
-  Parameters       : [:A]

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@onsiteMacro
@onsite((; params...) -> o(; params...); sites...)
+  Parameters       : [:A]

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@onsiteMacro
@onsite((; params...) -> o(; params...); sites...)
 @onsite((r; params...) -> o(r; params...); sites...)

Build a ParametricModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).

Site positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.

The difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.

@onsite((ω; params...) -> Σᵢᵢ(ω; params...); sites...)
 @onsite((ω, r; params...) -> Σᵢᵢ(ω, r; params...); sites...)

Special form of a parametric onsite potential meant to model a self-energy (see attach).

@onsite((i; params...) --> ...; sites...)
 @onsite((ω, i; params...) --> ...; sites...)

The --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.

Model algebra

Parametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.

Examples

julia> model = @onsite((r; dμ = 0) -> (r[1] + dμ) * I; sublats = :A) + @onsite((; dμ = 0) -> - dμ * I; sublats = :B)
@@ -741,7 +740,7 @@
   Onsites          : 8
   Hoppings         : 0
   Coordination     : 0.0
-  Parameters       : [:dμ]

See also

`onsite`, `hopping`, `@hopping`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@onsite!Macro
@onsite!((o; params...) -> o´(o; params...); sites...)
+  Parameters       : [:dμ]

See also

`onsite`, `hopping`, `@hopping`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`
source
Quantica.@onsite!Macro
@onsite!((o; params...) -> o´(o; params...); sites...)
 @onsite!((o, r; params...) -> o´(o, r; params...); sites...)

Build a uniform or position-dependent onsite term modifier, respectively, acting on sites selected by siteselector(; sites...) (see siteselector for details).

Site positions are r::SVector{E}, where E is the embedding dimension of the lattice. The original onsite potential is o, and the modified potential is , which is a function of o and possibly r. It may optionally also depend on parameters, enconded in params.

Modifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.

@onsite((o, i; params...) --> ...; sites...)

The --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.

Examples

julia> model = onsite(0); disorder = @onsite!((o; W = 0) -> o + W * rand())
 OnsiteModifier{ParametricFunction{1}}:
   Region            : any
@@ -759,4 +758,4 @@
   Onsites          : 200
   Hoppings         : 0
   Coordination     : 0.0
-  Parameters       : [:W]

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@hopping!`, `hamiltonian`, `OrbitalSliceArray`
source
+ Parameters : [:W]

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@hopping!`, `hamiltonian`, `OrbitalSliceArray`
source
diff --git a/dev/examples/index.html b/dev/examples/index.html index 4e8115bb..2716ba54 100644 --- a/dev/examples/index.html +++ b/dev/examples/index.html @@ -1,2 +1,2 @@ -Examples · Quantica.jl
+Examples · Quantica.jl
diff --git a/dev/index.html b/dev/index.html index 00276e32..575609d5 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · Quantica.jl

Quantica.jl logo

Quantica.jl is a Julia package for building generic tight-binding models and computing spectral and transport properties.

Installation

julia> import Pkg; Pkg.add("Quantica")

Quantica.jl requires Julia v1.9 or later. Some of its functionality, notably plotting, will become available only after using GLMakie, or some other plotting package from the Makie.jl family. Install GLMakie with

julia> import Pkg; Pkg.add("GLMakie")

Then, to begin using Quantica, just load it by doing

julia> using Quantica

(and possibly also e.g. using GLMakie if you need to plot Quantica objects).

Asking questions, reporting bugs

If you encounter problems, please read the tutorial and examples, your question is probably answered there. You can also check the docstring of each Quantica.jl function here or within the Julia REPL, by entering the function preceded by a ?, e.g. ?hamiltonian.

If you are still stuck, you may sometimes find me (@pablosanjose) at the Julia Slack or Julia Discourse.

If you believe you found a bug in Quantica.jl, please don't hesitate to file a GitHub issue, preferably with detailed instructions to reproduce it. Pull requests with fixes are also welcome!

+Home · Quantica.jl

Quantica.jl logo

Quantica.jl is a Julia package for building generic tight-binding models and computing spectral and transport properties.

Installation

julia> import Pkg; Pkg.add("Quantica")

Quantica.jl requires Julia v1.9 or later. Some of its functionality, notably plotting, will become available only after using GLMakie, or some other plotting package from the Makie.jl family. Install GLMakie with

julia> import Pkg; Pkg.add("GLMakie")

Then, to begin using Quantica, just load it by doing

julia> using Quantica

(and possibly also e.g. using GLMakie if you need to plot Quantica objects).

Asking questions, reporting bugs

If you encounter problems, please read the tutorial and examples, your question is probably answered there. You can also check the docstring of each Quantica.jl function here or within the Julia REPL, by entering the function preceded by a ?, e.g. ?hamiltonian.

If you are still stuck, you may sometimes find me (@pablosanjose) at the Julia Slack or Julia Discourse.

If you believe you found a bug in Quantica.jl, please don't hesitate to file a GitHub issue, preferably with detailed instructions to reproduce it. Pull requests with fixes are also welcome!

diff --git a/dev/objects.inv b/dev/objects.inv index c65363ea993884ef1b36d8210d6d48818ff26047..d852801704380b151d415a730b8b6bb3227f5b9a 100644 GIT binary patch delta 1603 zcmV-J2E6(64g3v|wFN!L($%??Y=W)Hy8{ zHSje=jrM+Gc!7T7HTJPK*F6m|!@t?TRLDu5V0?jA{X@@CQBrRhEsIHfH>%O)2Inv@ zCKas}(nH9M1#DkPT{9|Pzno<2MnTeDAgdZKl+5U!RLv-%{(lQ}<$h(PVFT`lEzt7* zefE*bRxgg|tuhfMS<`Y_;4go^MmW1Cf>cxqmS2yRdI%k8)xdAUQi{E6i6ztX$8JS4 zpppInx*UfXP3NMvzpag{EWqR;9-$=dx+g04(TSg9k>oR{!gi= zMQX^6qM{}x-mpC_aKl-xury1ZVeaJ#%!UVnC_N7fc#!4syM`OE20DM9@#N+?1agRM zH7dEoS%pP6QX0PPef03P&Pf5&BfPB!E`X~Ek}2x|q6za@0$xz;0nd=6#&<95lzDMz z)rWK=vo`6GOhIZ(nnO&=j;tVl<>Lnhfxj@d<1MJBZM3-Xh6|ih=hKQB)S9D4jv4_q znx@V!TOl4njORGt5nF$CO27a>D&tRfqFC)H<_#4D77|^zCq4Oo`4rl2F35w>2xL}< z0EGVg33*%wvSW~l*$wHninF(jY`HF6Ssro3LnV0}vbfIM`)vVt*NOvwf0jpUNn)m( zFl#Y|nW4@>sya0T@(f5nIEHL=9%8K=Y@`F`!r`>9k~B7TtXh8>*(8{h(g#wu$Bx~@ zjdyU9&mQhhg1}&{o)3?Mq|Dm$Ahc^E^ut2|EKw(OI;83PrJ8^Dm{#Q~{d<({C4~V3<%`s}1nc{Tj z-^F|PKQ{)_MccC``=FhsVp7hFBW#t8nm>4VdSg8@$a)= zxTMWarq_Q_XrqwZJF#YPh-l}fOCiW(V)q*QC*=Q-rn`Arjhmhcdy7oA(SQUbZb*<1 z$P$}oY#J|ph$g0Jc)fqZZR$h#-R2O|{V>7TyjexM+i(rncRO-um`w7%mO<09k)&xi_;yyX{rjA ztE6ZdjS7|d(PUdg)MG;@!<~!XyL%vn!X~ukbTBc8d~^!^x0G09P1$z0)`EydHf1YG z@!7O1vDhtXW(hBdq^E-Fc87j76%+=XoV^Np-{|&KSy)AK!9AvnIQikFjTs>env=&* zC9QwAY8PMYmAkm7ZOWTKZL_oTF~bDJGZ_|rH2R*n)g75Fl+puX@{>CPqMGk)_esLP z?bv694~5ajw?gk_Ls)`93xA1AFb99jkH5ZMgQKN6Ln>!??Ttp}!3iIa)!)YAak7P* zbxzB8o@4{-5p8^$S8UsVo=B^e<0b5ZMm2xj)|;fgu$@^f?1Jy#EB9^Um`n@WmB6H3 zO$FMCn?i3mXd|U|19&uc@IB~w!gJS&Jkjz_`w!?br1jfqSa1VMvsE}mqNHF;ygTUh z#|x+xH7&e;nvs)ZRQ?5fNH@vj3K{96H>5r_Y35OqgoJakCi{d!pfwd+_Qb}n2^z=4KR)`rO?+Vv%LR<8*(}Eexe85n3L)75cUoZIX0*lyFqpE7kEM_}cSLQd)g;|sLvA9{s~l6u2vSxoY~QOzzlIEQ&L zsc5Z`9ztd;Q2Rpano;rk<)m6S3Mt(IS=Df%WJdR-YDNL||68Cd_bVd}8)!FdftL60 zvyV)+dT~T=l|htbP0Q&7fAN1c!r46$q@qf&{Cb?Jhtxr?8v0FGO0jn>v1EGw*sW-W zG|E4qE|DerP-G@0SG;`iTb`nVvrAsBSr4QhFT}=pd`(cMUgS4Rn7zFP|dY%>{W98j;M( z5RlM+KOxV{Anh0gVs=CNT*cX2Mz&lRt}Kr@;$bFv9=Hi>?CD1ap@Me?0~`6aL6=j_2S;f9`yJT<#p zD_5TI*lNEf+9H2u3uBzO9Uoaf@_cXI6f`)LY1dAio0|WX)D+)>G1>zn>1}h0+GVCR zo%wfo@BZh;KsvNNYqAg8X(}e=d~$@XvdQKT-kqM=tc3hwzjDdBC|IpmS&^pk`KyZ_ zm#n6FJG<|P#?Xr)CuXu)1CbYlH`bPA-i3Yhu@St&GKYWo<-3IQE>uCJYe=*Taw@~9 zmFcbNAX3vb)huE+Ii-I|`7~j+07x>(*!rd7s8|99#VR z>=!O+vy*@6brjkt#P&|C85|{??j)FbF4PutisqeUT!Wd3>{HCcY zSgw-LGKvZ_^P`Ejrl`k;PQsmw-n)AsKw%TwavDs`As?MW|1BkktSQ^>);b|#$fj&1 zDL$KaC5GLSW>)ZmNO~%$Zg=QcQ=kxVa`tL42cqJOf1`U?Wwk4k3+_=J;^c>y7BiAB zXik3~Kb5rJs$D!FSMGM7wsUWSl$@QF#|)zs4|nJcQ8d)j17Y%$I|HIg-}&y7GXJ(y zpUr%zj5Z!-y-y8c2^m`WTU>%W_-lUr_3augEzKHIHM@In6qyG{d>pGkj>U1Zg{yT= z%Xpk*1M3lOe41Bm+kc-(tApd^=|H3UZ0mnb(q7osEC##a`}fLyoH&-I1?@^;(yyj~ zcH*Xp8xFaVQkMZeiXD6qIv()cwIWZnv(x?ydW>nkGztr@Kxvi9U#o&I_O zwW5w43kj#fsQe4|kZzL4Gh~z>y&?6XNi&a model_0 = hopping(1); # a possible non-interacting model\n\njulia> model_1 = @onsite((i; Φ = zerofield) --> Φ[i]);\n\njulia> model_2 = @hopping((i, j; Φ = zerofield) -> Φ[i, j]);Fock\n\njulia> h = lat |> hamiltonian(model_0 + model_1 + model_2)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Here model_1 corresponds to Hartree and onsite-Fock mean field terms, while model_2 corresponds to inter-site Fock terms. The default value Φ = zerofield is an singleton object that represents no interactions, so model_1 and model_2 vanish by default.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"We build the GreenFunction of h with g = greenfunction(h, solver; kw...) using the GreenSolver of choice\nWe construct a M::MeanField object using M = meanfield(g; potential = pot, other_options...)\nHere pot(r) is the charge-charge interaction potential between electrons. We can also specify hopselector directives to define which sites interacts, adding e.g. selector = (; range = 2) to other_options, to make sites at distance 2 interacting. See meanfield docstring for further details.\nWe evaluate this M with Φ0 = M(µ, kBT; params...).\nThis computes the density matrix at specific chemical potential µ and temperature kBT, and for specific parameters of h (possibly including Φ). Then it computes the appropriate Hartree and Fock terms, and stores them in the returned Φ0::OrbitalSliceMatrix, where Φ0ᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ. In normal systems, these terms read\ntexthartree_i = Q sum_k v_H(r_i-r_k) texttr(rho_kkQ)\ntextfock_ij = -v_F(r_i-r_j) Q rho_ij Q\nwhere v_H and v_F are Hartree and Fock charge-charge interaction potentials (by default equal to pot), and the charge operator is Q (equal to the identity by default, but can be changed to implement e.g. spin-spin interactions).\nWhen computing Φ0 we don't specify Φ in params, so that Φ0 is evaluated using the non-interacting model, hence its name.\nThe self-consistent condition can be tackled naively by iteration-until-convergence,","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Φ0 = M(µ, kBT; params...)\nΦ1 = M(µ, KBT; Φ = Φ0, params...)\nΦ2 = M(µ, KBT; Φ = Φ1, params...)\n...","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"A converged solution Φ, if found, should satisfy the fixed-point condition","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Φ_sol ≈ M(µ, KBT; Φ = Φ_sol, params...)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Then, the self-consistent Hamiltonian is given by h(; Φ = Φ_sol, params...).","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"The key problem is to actually find the fixed point of the M function. The naive iteration above is not optimal, and often does not converge. To do a better job we should use a dedicated fixed-point solver.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"note: Superconducting systems\nSuperconducting (Nambu) Hamiltonians obey the same equations for the Hartree and Fock mean fields, with a proper definition of Q, and an extra 1/2 coefficient in the Hartree trace, see the meanfield doctring.","category":"page"},{"location":"advanced/meanfield/#Using-an-external-fixed-point-solver","page":"Self-consistent mean fields","title":"Using an external fixed-point solver","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"We now show how to approach such a fixed-point problem. We will employ an external library to solve generic fixed-point problems, and show how to make it work with Quantica MeanField objects efficiently. Many generic fixed-point solver backends exist. Here we use the SIAMFANLEquations.jl package. It provides a simple utility aasol(f, x0) that computes the solution of f(x) = x with initial condition x0 using Anderson acceleration. This is an example of how it works to compute the fixed point of function f(x) = 1 + atan(x)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> f!(x, x0) = (x .= 1 .+ atan.(x0))\n\njulia> m = 3; x0 = rand(3); vstore = rand(3, 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> aasol(f!, x0, m, vstore).solution\n3-element Vector{Float64}:\n 2.132267725272934\n 2.132267725272908\n 2.132267725284556","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"The package requires as input an in-place version f! of the function f, and the preallocation of some storage space vstore (see the aasol documentation). The package, as a few others, also requires the variable x and the initial condition x0 to be an AbstractArray (or a scalar, but we need the former for our use case), hence the broadcast dots above. In our case we will therefore need to translate back and forth from an Φ::OrbitalSliceMatrix to a real vector x to pass it to aasol. This translation is achieved using Quantica's serialize/deserialize funcionality.","category":"page"},{"location":"advanced/meanfield/#Using-Serializers-with-fixed-point-solvers","page":"Self-consistent mean fields","title":"Using Serializers with fixed-point solvers","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"With the serializer functionality we can build a version of the fixed-point function f that operates on real vectors. Let's take a 1D Hamiltonian with a sawtooth potential, and build a Hartree mean field (note the fock = nothing keyword)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> h = LP.linear() |> supercell(4) |> onsite(r->r[1]) - hopping(1) + @onsite((i; phi = zerofield) --> phi[i]);\n\njulia> M = meanfield(greenfunction(h); onsite = 1, selector = (; range = 0), fock = nothing)\nMeanField{ComplexF64} : builder of Hartree-Fock-Bogoliubov mean fields\n Charge type : scalar (ComplexF64)\n Hartree pairs : 4\n Mean field pairs : 4\n Nambu : false\n\njulia> Φ0 = M(0.0, 0.0);\n\njulia> function f!(x, x0, (M, Φ0))\n Φ = M(0.0, 0.0; phi = deserialize(Φ0, x0))\n copy!(x, serialize(Φ))\n return x\n end;","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Then we can proceed as in the f(x) = 1 + atan(x) example","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> m = 2; x0 = serialize(Φ0); vstore = rand(length(x0), 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> x = aasol(f!, x0, m, vstore; pdata = (M, Φ0)).solution\n4-element Vector{ComplexF64}:\n 0.5658185030962436 + 0.0im\n 0.306216109313951 + 0.0im\n 0.06696362342872919 + 0.0im\n 0.06100176416107613 + 0.0im\n\njulia> h´ = h(; phi = deserialize(Φ0, x))\nHamiltonian{Float64,1,1}: Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 4 × 4\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 4\n Hoppings : 8\n Coordination : 2.0\n\njulia> h´[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 0.565819+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 1.30622+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.06696+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 3.061+0.0im","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Note that the content of pdata is passed by aasol as a third argument to f!. We use this to pass the serializer s and U parameter to use.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"note: Bring your own fixed-point solver!\nNote that fixed-point calculations can be tricky, and the search algorithm can have a huge impact in convergence (if the problem converges at all!). For this reason, Quantica.jl does not provide built-in fixed-point routines, only the functionality to write functions such as f above. Numerous packages exist for fixed-point computations in julia. Check NonlinearSolve.jl for one prominent metapackage.","category":"page"},{"location":"advanced/meanfield/#GreenSolvers-without-support-for-ParametricHamiltonians","page":"Self-consistent mean fields","title":"GreenSolvers without support for ParametricHamiltonians","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Some GreenSolver's, like GS.Spectrum or GS.KPM, do not support ParametricHamiltonians. In such cases, the approach above will fail, since it will not be possible to build g before knowing phi. In such cases one would need to rebuild the meanfield object at each step of the fixed-point solver. This is one way to do it.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> h = LP.linear() |> supercell(4) |> supercell |> onsite(1) - hopping(1) + @onsite((i; phi) --> phi[i]);\n\njulia> M´(phi = zerofield) = meanfield(greenfunction(h(; phi), GS.Spectrum()); onsite = 1, selector = (; range = 0), fock = nothing)\nM´ (generic function with 3 methods)\n\njulia> Φ0 = M´()(0.0, 0.0);\n\njulia> function f!(x, x0, (M´, Φ0))\n Φ = M´(deserialize(Φ0, x0))(0.0, 0.0)\n copy!(x, serialize(Φ))\n return x\n end;\n\njulia> m = 2; x0 = serialize(Φ0); vstore = rand(length(x0), 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> x = aasol(f!, x0, m, vstore; pdata = (M´, Φ0)).solution\n4-element Vector{ComplexF64}:\n 0.15596283661234628 + 0.0im\n 0.34403716338765444 + 0.0im\n 0.34403716338765344 + 0.0im\n 0.15596283661234572 + 0.0im","category":"page"},{"location":"advanced/nonspatial/#Non-spatial-models","page":"Non-spatial models","title":"Non-spatial models","text":"","category":"section"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"As briefly mentioned when discussing parametric models and modifiers, we have a special syntax that allows models to depend on sites directly, instead of on their spatial location. We call these non-spatial models. A simple example, with an onsite energy proportional to the site index","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> model = @onsite((i; p = 1) --> ind(i) * p)\nParametricModel: model with 1 term\n ParametricOnsiteTerm{ParametricFunction{1}}\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n Argument type : non-spatial\n Parameters : [:p]","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"or a modifier that changes a hopping between different cells","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> modifier = @hopping!((t, i, j; dir = 1) --> (cell(i) - cell(j))[dir])\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : non-spatial\n Parameters : [:dir]","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Note that we use the special syntax --> instead of ->. This indicates that the positional arguments of the function, here called i and j, are no longer site positions as up to now. These i, j are non-spatial arguments, as noted by the Argument type property shown above. Instead of a position, a non-spatial argument i represent an individual site, whose index is ind(i), its position is pos(i) and the cell it occupies on the lattice is cell(i).","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Technically i is of type CellSitePos, which is an internal type not meant for the end user to instantiate. One special property of this type, however, is that it can efficiently index OrbitalSliceArrays. We can use this to build a Hamiltonian that depends on an observable, such as a densitymatrix. A simple example of a four-site chain with onsite energies shifted by a potential proportional to the local density on each site:","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> h = LP.linear() |> onsite(2) - hopping(1) |> supercell(4) |> supercell;\n\njulia> h(SA[])\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 2.0+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 2.0+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.0+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 2.0+0.0im\n\njulia> g = greenfunction(h, GS.Spectrum());\n\njulia> ρ0 = densitymatrix(g[])(0.5, 0) ## density matrix at chemical potential `µ=0.5` and temperature `kBT = 0` on all sites\n4×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.138197+0.0im 0.223607+0.0im 0.223607+0.0im 0.138197+0.0im\n 0.223607+0.0im 0.361803+0.0im 0.361803+0.0im 0.223607+0.0im\n 0.223607+0.0im 0.361803+0.0im 0.361803+0.0im 0.223607+0.0im\n 0.138197+0.0im 0.223607+0.0im 0.223607+0.0im 0.138197+0.0im\n\njulia> hρ = h |> @onsite!((o, i; U = 0, ρ = ρ0) --> o + U * ρ[i])\nParametricHamiltonian{Float64,1,0}: Parametric Hamiltonian on a 0D Lattice in 1D space\n Bloch harmonics : 1\n Harmonic size : 4 × 4\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 4\n Hoppings : 6\n Coordination : 1.5\n Parameters : [:U, :ρ]\n\njulia> hρ(SA[]; U = 1, ρ = ρ0)\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 2.1382+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 2.3618+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.3618+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 2.1382+0.0im","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Note the ρ[i] above. This indexes ρ at site i. For a multiorbital hamiltonian, this will be a matrix (the local density matrix on each site i). Here it is just a number, either 0.138197 (sites 1 and 4) or 0.361803 (sites 2 and 3).","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"tip: Sparse vs dense\nThe method explained above to build a Hamiltonian hρ using --> supports all the SiteSelector and HopSelector functionality of conventional models. Therefore, although the density matrix computed above is dense, its application to the Hamiltonian is sparse: it only touches the onsite matrix elements in this case.","category":"page"},{"location":"tutorial/greenfunctions/#GreenFunctions","page":"GreenFunctions","title":"GreenFunctions","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Up to now we have seen how to define Lattices, Models, Hamiltonians and Bandstructures. Most problems require the computation of different physical observables for these objects, e.g. the local density of states or various transport coefficients. We reduce this general problem to the computation of the retarded Green function","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"G^r_ij(omega) = langle i(omega-H-Sigma(omega))^-1jrangle","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"where i, j are orbitals, H is the (possibly infinite) Hamiltonian matrix, and Σ(ω) is the self-energy coming from any coupling to other systems (typically described by their own AbstractHamiltonian).","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We split the problem of computing Gʳᵢⱼ(ω) of a given h::AbstractHamiltonian into four steps:","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Attach self-energies to h using the command oh = attach(h, args...). This produces a new object oh::OpenHamiltonian with a number of Contacts, numbered 1 to N\nUse g = greenfunction(oh, solver) to build a g::GreenFunction representing Gʳ (at arbitrary ω and i,j), where oh::OpenHamiltonian and solver::AbstractGreenSolver (see GreenSolvers below for available solvers)\nEvaluate gω = g(ω; params...) at fixed energy ω and model parameters, which produces a gω::GreenSolution\nSlice gω[sᵢ, sⱼ] or gω[sᵢ] == gω[sᵢ, sᵢ] to obtain Gʳᵢⱼ(ω) as a flat matrix, where sᵢ, sⱼ are either site selectors over sites spanning orbitals i,j, integers denoting contacts, 1 to N, or : denoting all contacts merged together.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: GreenSlice vs. GreenSolution\nThe two last steps can be interchanged, by first obtaining a gs::GreenSlice with gs = g[sᵢ, sⱼ] and then obtaining the Gʳᵢⱼ(ω) matrix with gs(ω; params...).","category":"page"},{"location":"tutorial/greenfunctions/#A-simple-example","page":"GreenFunctions","title":"A simple example","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Here is a simple example of the Green function of a 1D lead with two sites per unit cell, a boundary at cell = 0, and with no attached self-energies for simplicity","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> hlead = LP.square() |> supercell((1,0), region = r -> 0 <= r[2] < 2) |> hopping(1);\n\njulia> glead = greenfunction(hlead, GreenSolvers.Schur(boundary = 0))\nGreenFunction{Float64,2,1}: Green function of a Hamiltonian{Float64,2,1}\n Solver : AppliedSchurGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n Hamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> gω = glead(0.2) # we first fix energy to ω = 0.2\nGreenSolution{Float64,2,1}: Green function at arbitrary positions, but at a fixed energy\n\njulia> gω[cells = 1:2] # we now ask for the Green function between orbitals in the first two unit cells to the righht of the boundary\n4×4 Matrix{ComplexF64}:\n 0.1-0.858258im -0.5-0.0582576im -0.48-0.113394im -0.2+0.846606im\n -0.5-0.0582576im 0.1-0.858258im -0.2+0.846606im -0.48-0.113394im\n -0.48-0.113394im -0.2+0.846606im 0.104-0.869285im 0.44+0.282715im\n -0.2+0.846606im -0.48-0.113394im 0.44+0.282715im 0.104-0.869285im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that the result is a 4 x 4 matrix, because there are 2 orbitals (one per site) in each of the two unit cells. Note also that the GreenSolvers.Schur used here allows us to compute the Green function between distant cells with little overhead","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> @time gω[cells = 1:2];\n 0.000067 seconds (70 allocations: 6.844 KiB)\n\njulia> @time gω[cells = (SA[10], SA[100000])];\n 0.000098 seconds (229 allocations: 26.891 KiB)","category":"page"},{"location":"tutorial/greenfunctions/#GreenSolvers","page":"GreenFunctions","title":"GreenSolvers","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The currently implemented GreenSolvers (abbreviated as GS) are the following","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.SparseLU()\nFor bounded (L=0) AbstractHamiltonians. Default for L=0.\nUses a sparse LU factorization to compute the inverse of ⟨i|ω - H - Σ(ω)|j⟩, where Σ(ω) is the self-energy from the contacts.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Spectrum(; spectrum_kw...)\nFor bounded (L=0) Hamiltonians. This solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first.\nUses a diagonalization of H, obtained with spectrum(H; spectrum_kw...), to compute the G⁰ᵢⱼ using the Lehmann representation ∑ₖ⟨i|ϕₖ⟩⟨ϕₖ|j⟩/(ω - ϵₖ). Any eigensolver supported by spectrum can be used here. If there are contacts, it dresses G⁰ using a T-matrix approach, G = G⁰ + G⁰TG⁰.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.KPM(order = 100, bandrange = missing, kernel = I)\nFor bounded (L=0) Hamiltonians, and restricted to sites belonging to contacts (see the section on Contacts).\nIt precomputes the Chebyshev momenta, and incorporates the contact self energy with a T-matrix approach.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Schur(boundary = Inf)\nFor 1D (L=1) AbstractHamiltonians with only nearest-cell coupling. Default for L=1.\nUses a deflating Generalized Schur (QZ) factorization of the generalized eigenvalue problem to compute the unit-cell self energies. The Dyson equation then yields the Green function between arbitrary unit cells, which is further dressed using a T-matrix approach if the lead has any attached self-energy.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Bands(bandsargs...; boundary = missing, bandskw...)\nFor unbounded (L>0) Hamiltonians.\nIt precomputes a bandstructure b = bands(h, bandsargs...; kw..., split = false) and then uses analytic expressions for the contribution of each subband simplex to the GreenSolution. If boundary = dir => cell_pos, it takes into account the reflections on an infinite boundary perpendicular to Bravais vector number dir, so that all sites with cell index c[dir] <= cell_pos are removed. Contacts are incorporated using a T-matrix approach.\nTo retrieve the bands from a g::GreenFunction that used the GS.Bands solver, we may use bands(g).","category":"page"},{"location":"tutorial/greenfunctions/#Attaching-Contacts","page":"GreenFunctions","title":"Attaching Contacts","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"A self energy Σ(ω) acting of a finite set of sites of h (i.e. on a LatticeSlice of lat = lattice(h)) can be incorporated using the attach command. This defines a new Contact in h. The general syntax is oh = attach(h, args...; sites...), where the sites directives define the Contact LatticeSlice (lat[siteselector(; sites...)]), and args can take a number of forms.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The supported attach forms are the following","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Generic self-energy\nattach(h, gs::GreenSlice, coupling::AbstractModel; sites...)\nThis is the generic form of attach, which couples some sites i of a g::Greenfunction (defined by the slice gs = g[i]), to sites of h using a coupling model. This results in a self-energy Σ(ω) = V´⋅gs(ω)⋅V on h sites, where V and V´ are couplings matrices given by coupling.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Dummy self-energy\nattach(h, nothing; sites...)\nThis form merely defines a new contact on the specified sites, but adds no actual self-energy to it. It is meant as a way to refer to some sites of interest using the g[i::Integer] slicing syntax for GreenFunctions, where i is the contact index.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Model self-energy\nattach(h, model::AbstractModel; sites...)\nThis form defines a self-energy Σᵢⱼ(ω) in terms of model, which must be composed purely of parametric terms (@onsite and @hopping) that have ω as first argument, as in e.g. @onsite((ω, r) -> Σᵢᵢ(ω, r)) or @hopping((ω, r, dr) -> Σᵢⱼ(ω, r, dr)). This is a modellistic approach, wherein the self-energy is not computed from the properties of another AbstractHamiltonian, but rather has an arbitrary form defined by the user.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Matched lead self-energy\nattach(h, glead::GreenFunction; reverse = false, transform = identity, sites...)\nHere glead is a GreenFunction of a 1D lead, possibly with a boundary.\nWith this syntax sites must select a number of sites in h whose position match (after applying transform to them and modulo an arbitrary displacement) the sites in the unit cell of glead. Then, the coupling between these and the first unit cell of glead on the positive side of the boundary will be the same as between glead unitcells, i.e. V = hlead[(1,)], where hlead = hamiltonian(glead).\nIf reverse == true, the lead is reversed before being attached, so that h is coupled through V = hlead[(-1,)] to the first unitcell on the negative side of the boundary. If there is no boundary, the cell = 0 unitcell of the glead is used.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Generic lead self-energy\nattach(h, glead::GreenFunction, model::AbstractModel; reverse = false, transform = identity, sites...)\nThe same as above, but without any restriction on sites. The coupling between these and the first unit cell of glead (transformed by transform) is constructed using model::TightbindingModel. The \"first unit cell\" is defined as above.","category":"page"},{"location":"tutorial/greenfunctions/#A-more-advanced-example","page":"GreenFunctions","title":"A more advanced example","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Let us define the classical example of a multiterminal mesoscopic junction. We choose a square lattice, and a circular central region of radius 10, with four leads of width 5 coupled to it at right angles.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We first define a single lead Greenfunction and the central Hamiltonian","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> glead = LP.square() |> onsite(4) - hopping(1) |> supercell((1, 0), region = r -> abs(r[2]) <= 5/2) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> hcentral = LP.square() |> onsite(4) - hopping(1) |> supercell(region = RP.circle(10) | RP.rectangle((22, 5)) | RP.rectangle((5, 22)));","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The two rectangles overlayed on the circle above create the stubs where the leads will be attached:","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Central","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We now attach glead four times using the Matched lead syntax","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> Rot = r -> SA[0 -1; 1 0] * r; # 90º rotation function\n\njulia> g = hcentral |>\n attach(glead, region = r -> r[1] == 11) |>\n attach(glead, region = r -> r[1] == -11, reverse = true) |>\n attach(glead, region = r -> r[2] == 11, transform = Rot) |>\n attach(glead, region = r -> r[2] == -11, reverse = true, transform = Rot) |>\n greenfunction\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 4\n Contact solvers : (SelfEnergySchurSolver, SelfEnergySchurSolver, SelfEnergySchurSolver, SelfEnergySchurSolver)\n Contact sizes : (5, 5, 5, 5)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 353 × 353\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 1320\n Coordination : 3.73938\n\njulia> qplot(g, children = (; selector = siteselector(; cells = 1:5), sitecolor = :blue))","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Multiterminal","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that since we did not specify the solver in greenfunction, the L=0 default GS.SparseLU() was taken.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We can also visualize glead, which is defined on a 1D lattice with a boundary. Boundary cells are shown by default in red","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: The GreenFunction <-> AbstractHamiltonian relation\nIts important un appreciate that a g::GreenFunction represents the retarded Green function between sites in a given AbstractHamiltonian, but not on sites of the coupled AbstractHamiltonians of its attached self-energies. Therefore, gcentral above cannot yield observables in the leads (blue sites above), only on the red sites. To obtain observables in a given lead, its GreenFunction must be constructed, with an attached self-energy coming from the central region plus the other three leads.","category":"page"},{"location":"tutorial/greenfunctions/#Slicing-and-evaluation","page":"GreenFunctions","title":"Slicing and evaluation","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"As explained above, a g::GreenFunction represents a Green function of an OpenHamiltonian (i.e. AbstractHamiltonian with zero or more self-energies), but it does so for any energy ω or lattice sites.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"- To specify `ω` (plus any parameters `params` in the underlying `AbstractHamiltonian`) we use the syntax `g(ω; params...)`, which yields an `gω::GreenSolution`\n- To specify source (`sⱼ`) and drain (`sᵢ`) sites we use the syntax `g[sᵢ, sⱼ]` or `g[sᵢ] == g[sᵢ,sᵢ]`, which yields a `gs::GreenSlice`. `sᵢ` and `sⱼ` can be `SiteSelectors(; sites...)`, or an integer denoting a specific contact (i.e. sites with an attached self-energy) or `:` denoting all contacts merged together.\n- If we specify both of the above we get the Green function between the orbitals of the specified sites at the specified energy, in the form of an `OrbitalSliceMatrix`, which is a special `AbstractMatrix` that knows about the orbitals in the lattice over which its matrix elements are defined.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Let us see this in action using the example from the previous section","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g[1, 3]\nGreenSlice{Float64,2,0}: Green function at arbitrary energy, but at a fixed lattice positions\n\njulia> g(0.2)\nGreenSolution{Float64,2,0}: Green function at arbitrary positions, but at a fixed energy\n\njulia> g(0.2)[1, 3]\n5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -2.56906+0.000123273im -4.28767+0.00020578im -4.88512+0.000234514im -4.28534+0.00020578im -2.5664+0.000123273im\n -4.28767+0.00020578im -7.15613+0.00034351im -8.15346+0.000391475im -7.15257+0.00034351im -4.2836+0.000205781im\n -4.88512+0.000234514im -8.15346+0.000391475im -9.29002+0.000446138im -8.14982+0.000391476im -4.88095+0.000234514im\n -4.28534+0.00020578im -7.15257+0.00034351im -8.14982+0.000391476im -7.14974+0.000343511im -4.28211+0.000205781im\n -2.5664+0.000123273im -4.2836+0.000205781im -4.88095+0.000234514im -4.28211+0.000205781im -2.56469+0.000123273im\n\njulia> g(0.2)[siteselector(region = RP.circle(1, (0.5, 0))), 3]\n2×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.0749214+3.15744e-8im 0.124325+5.27948e-8im 0.141366+6.01987e-8im 0.124325+5.27948e-8im 0.0749214+3.15744e-8im\n -0.374862+2.15287e-5im -0.625946+3.5938e-5im -0.712983+4.09561e-5im -0.624747+3.59379e-5im -0.37348+2.15285e-5im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: Fixing parameters\nIn the same way we can fix all parameters of a h::ParametricHamiltonian with h´=h(;params...) (which produces a h´::Hamiltonian without any parametric dependencies), we can similarly fix all parameters in a g::GreenFunction (or g::GreenSlice) with g(; params...), which produces a new GreenFunction (or GreenSlice). Note that, like in the case of h, this fixes all parameters. Any parameter that is not specify will be fixed to its default value.","category":"page"},{"location":"tutorial/greenfunctions/#Diagonal-slices","page":"GreenFunctions","title":"Diagonal slices","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"There is a special form of slicing that requests just the diagonal of a given g[sᵢ] == g[sᵢ,sᵢ]. It uses the syntax g[diagonal(sᵢ)]. Let us see it in action in a multiorbital example in 2D","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g = HP.graphene(a0 = 1, t0 = 1, orbitals = 2) |> greenfunction\nGreenFunction{Float64,2,2}: Green function of a Hamiltonian{Float64,2,2}\n Solver : AppliedBandsGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n Hamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> g(0.5)[diagonal(cells = (0, 0))]\n4-element OrbitalSliceVector{Vector{ComplexF64}}:\n -0.3497363468480622 - 0.3118358260294266im\n -0.3497363468271048 - 0.31183582602942655im\n -0.3497363468402952 - 0.31183582602942667im\n -0.34973634686125243 - 0.3118358260294267im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that we get an OrbitalSliceVector, which is equal to the diagonal diag(g(0.5)[cells = (0, 0)]). Like the g OrbitalSliceMatrix, this vector is resolved in orbitals, of which there are two per site and four per unit cell in this case. Using diagonal(sᵢ; kernel = K) we can collect all the orbitals of different sites, and compute tr(g[site, site] * K) for a given matrix K. This is useful to obtain spectral densities. In the above example, and interpreting the two orbitals per site as the electron spin, we could obtain the spin density along the x axis, say, using σx = SA[0 1; 1 0] as kernel,","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g(0.5)[diagonal(cells = (0, 0), kernel = SA[0 1; 1 0])]\n2-element OrbitalSliceVector{Vector{ComplexF64}}:\n 4.26186044627701e-12 - 2.2846013280115095e-17im\n -4.261861877528737e-12 + 1.9177925470610777e-17im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"which is zero in this spin-degenerate case","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: Slicing `OrbitalSliceArray`s\nAn v::OrbitalSliceVector and m::OrbitalSliceMatrix are both a::OrbitalSliceArray, and wrap conventional arrays, with e.g. conventional axes. They also provide, however, orbaxes(a), which are a tuple of OrbitalSliceGrouped. These are LatticeSlices that represent orbitals grouped by sites. They allow an interesting additional functionality. You can index v[sitelector(...)] or m[rowsiteselector, colsiteselector] to obtain a new OrbitalSliceArray of the selected rows and cols. The full machinery of siteselector applies. One can also use a lower-level v[sites(cell_index, site_indices)] to obtain an unwrapped AbstractArray, without building new orbaxes. See OrbitalSliceArray for further details.","category":"page"},{"location":"tutorial/greenfunctions/#Visualizing-a-Green-function","page":"GreenFunctions","title":"Visualizing a Green function","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We can use qplot to visualize a GreenSolution in space. Here we define a bounded square lattice with an interesting shape, and attach a model self-energy to the right. Then we compute the Green function from each orbital in the contact to any other site in the lattice, and compute the norm over contact sites. The resulting vector is used as a shader for the color and radius of sites when plotting the system","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> h = LP.square() |> onsite(4) - hopping(1) |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1]))));\n\njulia> g = h |> attach(@onsite(ω -> -im), region = r -> r[1] ≈ 47) |> greenfunction;\n\njulia> gx1 = sum(abs2, g(0.1)[siteselector(), 1], dims = 2);\n\njulia> qplot(h, hide = :hops, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Green","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"warning: Caveat for multiorbital systems\nSince, currently, g(ω)[sᵢ, sⱼ] yields a Matrix over orbitals (instead of over sites), the above example requires single-orbital sites to work. In the future we will probably introduce a way to slice a GreenSolution over sites, similar to the way diagonal works. For the moment, one can use observables like ldos for visualization (see next section), which are all site-based by default.","category":"page"},{"location":"tutorial/lattices/#Lattices","page":"Lattices","title":"Lattices","text":"","category":"section"},{"location":"tutorial/lattices/#Constructing-a-Lattice-from-scratch","page":"Lattices","title":"Constructing a Lattice from scratch","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Consider a lattice like graphene's. It has two sublattices, A and B, forming a 2D honeycomb pattern in space. The position of site A and B inside the unitcell are [0, -a0/(2√3)] and [0, a0/(2√3)], respectively. The Bravais vectors are A₁, A₂ = a0 * [± cos(π/3), sin(π/3)]. If we set the lattice constant to a0 = √3 (so the carbon-carbon distance is 1), one way to build this lattice in Quantica.jl would be","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> A₁, A₂ = √3 .* (cos(π/3), sin(π/3)),\n √3 .* (-cos(π/3), sin(π/3));\n\njulia> sA, sB = sublat((0, -1/2), name = :A),\n sublat((0, 1/2), name = :B);\n\njulia> lattice(sA, sB, bravais = (A₁, A₂))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.866025, 1.5], [-0.866025, 1.5]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Tuple, SVector and SMatrix\nNote that we have used Tuples, such as (0, 1/2) instead of Vectors, like [0, 1/2]. In Julia small-length Tuples are much more efficient as containers than Vectors, since their length is known and fixed at compile time. Static vectors (SVector) and matrices (SMatrix) are also available to Quantica, which are just as efficient as Tuples, and they also implement linear algebra operations. They may be entered as e.g. SA[0, 1/2] and SA[1 0; 0 1], respectively. For efficiency, always use Tuple, SVector and SMatrix in Quantica.jl where possible.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"If we don't plan to address the two sublattices individually, we could also fuse them into one, like","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = lattice(sublat((0, 1/2), (0, -1/2)), bravais = (A₁, A₂))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.866025, 1.5], [-0.866025, 1.5]]\n Sublattices : 1\n Names : (:A,)\n Sites : (2,) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"This lattice has type Lattice{T,E,L}, with T = Float64 the numeric type of position coordinates, E = 2 the dimension of embedding space, and L = 2 the number of Bravais vectors (i.e. the lattice dimension). Both T and E, and even the Sublat names can be overridden when creating a lattice. One can also provide the Bravais vectors as a matrix, with each Aᵢ as a column.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> Amat = √3 * SA[-cos(π/3) cos(π/3); sin(π/3) sin(π/3)];\n\njulia> lat´ = lattice(sA, sB, bravais = Amat, type = Float32, dim = 3, names = (:C, :D))\nLattice{Float32,3,2} : 2D lattice in 3D space\n Bravais vectors : Vector{Float32}[[-0.866025, 1.5, 0.0], [0.866025, 1.5, 0.0]]\n Sublattices : 2\n Names : (:C, :D)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Advanced: `dim = Val(E)` vs. `dim = E`\nFor the dim keyword above we can alternatively use dim = Val(3), which is slightly more efficient, because the value is encoded as a type. This is a \"Julia thing\" (related to the concept of type stability), and can be ignored upon a first contact with Quantica.jl.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"One can also convert an existing lattice like the above to have a different type, embedding dimension, Bravais vectors and Sublat names with lattice(lat; kw...). For example","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat´´ = lattice(lat´, type = Float16, dim = 2, names = (:Boron, :Nitrogen))\nLattice{Float16,2,2} : 2D lattice in 2D space\n Bravais vectors : Vector{Float16}[[-0.866, 1.5], [0.866, 1.5]]\n Sublattices : 2\n Names : (:Boron, :Nitrogen)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"A list of site positions in a lattice lat can be obtained with sites(lat), or sites(lat, sublat) to restrict to a specific sublattice","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> sites(lat´´)\n2-element Vector{SVector{2, Float16}}:\n [0.0, -0.5]\n [0.0, 0.5]\n\njulia> sites(lat´´, :Nitrogen)\n1-element view(::Vector{SVector{2, Float16}}, 2:2) with eltype SVector{2, Float16}:\n [0.0, 0.5]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Similarly, the Bravais matrix of a lat can be obtained with bravais_matrix(lat).","category":"page"},{"location":"tutorial/lattices/#Lattice-presets","page":"Lattices","title":"Lattice presets","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Quantica.jl provides a range of presets. A preset is a pre-built object of some type. In particular we have Lattice presets, defined in the submodule LatticePresets (also called LP for convenience), that include a number of classical lattices in different dimensions:","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"LP.linear: linear 1D lattice\nLP.square: square 2D lattice\nLP.honeycomb: honeycomb 2D lattice\nLP.cubic: cubic 3D lattice\nLP.bcc: body-centered cubic 3D lattice\nLP.fcc: face-centered cubic 3D lattice","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To obtain a lattice from a preset one simply calls it, e.g. LP.honecyomb(; kw...). One can modify any of these LatticePresets by passing a bravais, type, dim or names keyword. One can also use a new keyword a0 for the lattice constant (a0 = 1 by default). The lattice lat´´ above can thus be also obtained with","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat´´ = LP.honeycomb(a0 = √3, type = Float16, names = (:Boron, :Nitrogen))\nLattice{Float16,2,2} : 2D lattice in 2D space\n Bravais vectors : Vector{Float16}[[0.866, 1.5], [-0.866, 1.5]]\n Sublattices : 2\n Names : (:Boron, :Nitrogen)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Quantica's Presets library\nQuantica comes with four submodules that provide different kinds of presets: LatticePresets (LP), HamiltonianPresets (HP), RegionPresets (RP) and ExternalPresets (EP). LP provides a collection of standard lattices, HP some premade model Hamiltonians such as HP.graphene or HP.twisted_bilayer_graphene, RP some geometric regions such as RP.circle or RP.cuboid, and EP some importers of externally produced objects such as EP.wannier90 to import Wannier90 files (see Advanced for details on the latter). This library of presets is expected to grow with time. The docstring for the submodule or the preset function can be queried for a description of the available options.","category":"page"},{"location":"tutorial/lattices/#Visualization","page":"Lattices","title":"Visualization","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To produce an interactive visualization of Lattices or other Quantica.jl object you need to load GLMakie.jl, CairoMakie.jl or some other plotting backend from the Makie repository (i.e. do using GLMakie, see also Installation). Then, a number of new plotting functions will become available. The main one is qplot. A Lattice is represented, by default, as the sites in a unitcell plus the Bravais vectors.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> using GLMakie\n\njulia> lat = LP.honeycomb()\n\njulia> qplot(lat, hide = nothing)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"Honeycomb","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"qplot accepts a large number of keywords to customize your plot. In the case of lattice, most of these are passed over to the function plotlattice, specific to Lattices and Hamiltonians. In the case above, hide = nothing means \"don't hide any element of the plot\". See the qplot and plotlattice docstrings for details.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: GLMakie.jl vs CairoMakie.jl\nGLMakie.jl is optimized for interactive GPU-accelerated, rasterized plots. If you need to export to PDF for publications or display plots inside a Jupyter notebook, use CairoMakie.jl instead, which in general renders non-interactive, but vector-based plots.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: User-defined defaults for `qplot`\nThe command qplotdefaults(; axis, figure) can be used to define the default value of figure and axis keyword arguments of qplot. Example: to fix the size of all subsequent plots, do qplotdefaults(; figure = (size = (1000, 1000),)).","category":"page"},{"location":"tutorial/lattices/#siteselectors","page":"Lattices","title":"SiteSelectors","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"A central concept in Quantica.jl is that of a \"selector\". There are two types of selectors, SiteSelectors and HopSelectors. SiteSelectors are a set of directives or rules that define a subset of its sites. SiteSelector rules are defined through three keywords:","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"region: a boolean function of allowed site positions r.\nsublats: allowed sublattices of selected sites\ncells: allowed cell indices of selected sites","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Similarly, HopSelectors can be used to select a number of site pairs, and will be used later to define hoppings in tight-binding models (see further below).","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"As an example, let us define a SiteSelector that picks all sites belonging to the :B sublattice of a given lattice within a circle of radius 10","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> s = siteselector(region = r -> norm(r) <= 10, sublats = :B)\nSiteSelector: a rule that defines a finite collection of sites in a lattice\n Region : Function\n Sublattices : B\n Cells : any","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Note that this selector is defined independently of the lattice. To apply it to a lattice lat we do lat[s], which results in a LatticeSlice (i.e. a finite portion, or slice, of lat)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = LP.honeycomb(); lat[s]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 363\n Cell range : ([-11, -11], [11, 11])\n Total sites : 363","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"The Cell range above are the corners of a bounding box in cell-index space that contains all unit cell indices with at least one selected site.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Let's plot it","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> qplot(lat[s], hide = ())","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"A","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: qplot selector\nThe above qplot(lat[s]) can also be written as qplot(lat, selector = s), which will be useful when plotting AbstractHamiltonians.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Sites of a LatticeSlice\nCollect the site positions of a LatticeSlice into a vector with collect(sites(ls)). If you do sites(ls) instead, you will get a lazy generator that can be used to iterate efficiently among site positions without allocating them in memory.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Apart from region and sublats we can also restrict the unitcells by their cell index. For example, to select all sites in unit cells within the above bounding box we can do","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> s´ = siteselector(cells = CartesianIndices((-11:11, -11:11)))\nSiteSelector: a rule that defines a finite collection of sites in a lattice\n Region : any\n Sublattices : any\n Cells : CartesianIndices((-11:11, -11:11))\n\njulia> lat[s´]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 529\n Cell range : ([-11, -11], [11, 11])\n Total sites : 1058","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can often omit constructing the SiteSelector altogether by using the keywords directly","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> ls = lat[cells = n -> 0 <= n[1] <= 2 && abs(n[2]) < 3, sublats = :A]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 15\n Cell range : ([0, -2], [2, 2])\n Total sites : 15","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Selectors are very expressive and powerful. Do check siteselector and hopselector docstrings for more details.","category":"page"},{"location":"tutorial/lattices/#Transforming-lattices","page":"Lattices","title":"Transforming lattices","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can transform lattices using supercell, reverse, transform, translate.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"As a periodic structure, the choice of the unitcell in an unbounded lattice is, to an extent, arbitrary. Given a lattice lat we can obtain another with a unit cell 3 times larger with supercell(lat, 3)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = supercell(LP.honeycomb(), 3)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 2.598076], [-1.5, 2.598076]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (9, 9) --> 18 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"More generally, given a lattice lat with Bravais matrix Amat = bravais_matrix(lat), we can obtain a larger one with Bravais matrix Amat´ = Amat * S, where S is a square matrix of integers. In the example above, S = SA[3 0; 0 3]. The columns of S represent the coordinates of the new Bravais vectors in the basis of the old Bravais vectors. A more general example with e.g. S = SA[3 1; -1 2] can be written either in terms of S or of its columns","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> supercell(lat, SA[3 1; -1 2]) == supercell(lat, (3, -1), (1, 2))\ntrue","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can also use supercell to reduce the number of Bravais vectors, and hence the lattice dimensionality. To construct a new lattice with a single Bravais vector A₁´ = 3A₁ - A₂, just omit the second one","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> supercell(lat, (3, -1))\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[6.0, 5.196152]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (27, 27) --> 54 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Its important to note that the lattice will be bounded along directions different from the specified Bravais vectors. With the syntax above, the new unitcell will be minimal. We may however define how many sites to include in the new unitcell by adding a SiteSelector directive to be applied in the non-periodic directions. For example, to create a 10 * a0 wide, honeycomb nanoribbon we can do","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = supercell(LP.honeycomb(), (1,-1), region = r -> -5 <= r[2] <= 5)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 0.0]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (12, 12) --> 24 total per unit cell\n\njulia> qplot(lat[cells = -7:7])","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"Honeycomb","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: No need to build selectors explicitly\nNote that we we didn't build a siteselector(region = ...) object to pass it to supercell. Instead, as shown above, we passed the corresponding keywords directly to supercell, which then takes care to build the selector internally.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To simply reverse the direction of the Bravais vectors of a lattice, while leaving the site positions unchanged, use reverse (or reverse! to do it in-place)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> reverse(LP.square())\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[-1.0, -0.0], [-0.0, -1.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To transform a lattice, so that site positions r become f(r) use transform","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> f(r) = SA[0 1; 1 0] * r\nf (generic function with 1 method)\n\njulia> rotated_honeycomb = transform(LP.honeycomb(a0 = √3), f)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 0.866025], [1.5, -0.866025]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> sites(rotated_honeycomb)\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 0.0]\n [0.5, 0.0]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To translate a lattice by a displacement vector δr use translate","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> δr = SA[0, 1];\n\njulia> sites(translate(rotated_honeycomb, δr))\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 1.0]\n [0.5, 1.0]","category":"page"},{"location":"tutorial/lattices/#Currying:-chaining-transformations-with-the-operator","page":"Lattices","title":"Currying: chaining transformations with the |> operator","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Many functions in Quantica.jl have a \"curried\" version that allows them to be chained together using the pipe operator |>.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"note: Definition of currying\nThe curried version of a function f(x1, x2...) is f´ = x1 -> f(x2...), so that the curried form of f(x1, x2...) is x2 |> f´(x2...), or f´(x2...)(x1). This gives the first argument x1 a privileged role. Users of object-oriented languages such as Python may find this use of the |> operator somewhat similar to the way the dot operator works there (i.e. x1.f(x2...)).","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"The last example above can then be written as","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> LP.honeycomb(a0 = √3) |> transform(f) |> translate(δr) |> sites\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 1.0]\n [0.5, 1.0]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"This type of curried syntax is natural in Quantica, and will be used extensively in this tutorial.","category":"page"},{"location":"tutorial/glossary/#Glossary","page":"Glossary","title":"Glossary","text":"","category":"section"},{"location":"tutorial/glossary/","page":"Glossary","title":"Glossary","text":"This is a summary of the type of objects you will be studying.","category":"page"},{"location":"tutorial/glossary/","page":"Glossary","title":"Glossary","text":"Sublat: a sublattice, representing a number of identical sites within the unit cell of a bounded or unbounded lattice. Each site has a position in an E-dimensional space (E is called the embedding dimension). All sites in a given Sublat will be able to hold the same number of orbitals, and they can be thought of as identical atoms. Each Sublat in a Lattice can be given a unique name, by default :A, :B, etc.\nLattice: a collection of Sublats plus a collection of L Bravais vectors that define the periodicity of the lattice. A bounded lattice has L=0, and no Bravais vectors. A Lattice with L > 0 can be understood as a periodic (unbounded) collection of unit cells, each containing a set of sites, each of which belongs to a different sublattice.\nSiteSelector: a rule that defines a subset of sites in a Lattice (not necessarily restricted to a single unit cell)\nHopSelector: a rule that defines a subset of site pairs in a Lattice (not necessarily restricted to the same unit cell)\nLatticeSlice: a finite subset of sites in a Lattice, defined by their cell index (an L-dimensional integer vector, usually denoted by n or cell) and their site index within the unit cell (an integer). A LatticeSlice an be constructed by combining a Lattice and a (bounded) SiteSelector.\nAbstractModel: either a TightBindingModel or a ParametricModel\nTightBindingModel: a set of HoppingTerms and OnsiteTerms\nOnsiteTerm: a rule that, applied to a single site, produces a scalar or a (square) matrix that represents the intra-site Hamiltonian elements (single or multi-orbital)\nHoppingTerm: a rule that, applied to a pair of sites, produces a scalar or a matrix that represents the inter-site Hamiltonian elements (single or multi-orbital)\nParametricModel: a set of ParametricOnsiteTerms and ParametricHoppingTerms\nParametricOnsiteTerm: an OnsiteTerm that depends on a set of free parameters that can be adjusted, and that may or may not have a default value\nParametricHoppingTerm: a HoppingTerm that depends on parameters, like ParametricOnsiteTerm above\nAbstractHamiltonian: either a Hamiltonian or a ParametricHamiltonian\nHamiltonian: a Lattice combined with a TightBindingModel.\nIt also includes a specification of the number of orbitals in each Sublat in the Lattice. A Hamiltonian represents a tight-binding Hamiltonian sharing the same periodicity as the Lattice (it is translationally invariant under Bravais vector shifts).\nParametricHamiltonian: like the above, but using a ParametricModel, which makes it dependent on a set of free parameters that can be efficiently adjusted.\nAn h::AbstractHamiltonian can be used to produce a Bloch matrix h(ϕ; params...) of the same size as the number of orbitals per unit cell, where ϕ = [ϕᵢ...] are Bloch phases and params are values for the free parameters, if any.\nSpectrum: the set of eigenpairs (eigenvalues and corresponding eigenvectors) of a Bloch matrix. It can be computed with a number of EigenSolvers.\nBandstructure: a collection of spectra, evaluated over a discrete mesh (typically a discretization of the Brillouin zone), that is connected to its mesh neighbors into a linearly-interpolated approximation of the AbstractHamiltonian's bandstructure.\nSelfEnergy: an operator Σ(ω) defined to act on a LatticeSlice of an AbstractHamiltonian that depends on energy ω.\nOpenHamiltonian: an AbstractHamiltonian combined with a set of SelfEnergies\nGreenFunction: an OpenHamiltonian combined with an AbstractGreenSolver, which is an algorithm that can in general compute the retarded or advanced Green function at any energy between any subset of sites of the underlying lattice.\nGreenSlice: a GreenFunction evaluated on a specific set of sites, but at an unspecified energy\nGreenSolution: a GreenFunction evaluated at a specific energy, but on an unspecified set of sites\nOrbitalSliceArray: an AbstractArray that can be indexed with a SiteSelector, in addition to the usual scalar indexing. Particular cases are OrbitalSliceMatrix and OrbitalSliceVector. This is the most common type obtained from GreenFunctions and observables obtained from them.\nObservables: Supported observables, obtained from Green functions using various algorithms, include local density of states, density matrices, current densities, transmission probabilities, conductance and Josephson currents","category":"page"},{"location":"advanced/wannier90/#Wannier90-imports","page":"Wannier90 imports","title":"Wannier90 imports","text":"","category":"section"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"A common way to obtain quantitative tight-binding models of materials is to Wannierize density-functional-theory (DFT) bandstructures. In a nutshell, this procedure consists in obtaining a basis set of a subspace of some DFT bandstructure, subject to the condition that the obtained states are maximally localized. A popular implementation of this algorithm is (Wannier90)[https://wannier.org]. Among other things, this tool produces output files that encode a tight-binding Hamiltonian for the material and the matrix elements of the position operator in the maximally localized Wannier basis.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Quantica.jl includes a function that can import Wannier90 tight-binding files. By default these files are 3D systems","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = ExternalPresets.wannier90(\"wannier_tb.dat\")\nWannierBuilder{Float64,3} : 3-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 755\n elements : 36388\n modifiers : 0","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"In this case, however, the model in the \"wannier_tb.dat\" file is a 2D MoS2 crystal. We can project out all out-of-plane matrix elements by specifying the dimension with dim. We can also drop any Hamiltonian matrix element smaller than, say htol = 1e-5, and any position matrix element of norm smaller than rtol = 1e-4. This greatly simplifies the problem","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = ExternalPresets.wannier90(\"wannier_tb.dat\"; dim = 2, htol = 1e-5, rtol = 1e-4)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7510\n modifiers : 0","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"This object can then be converted into a Hamiltonian h or a position operator r","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> h = hamiltonian(w)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 10\n Hoppings : 7500\n Coordination : 750.0\n\njulia> r = position(w)\nBarebonesOperator{2}: a simple collection of 2D Bloch harmonics\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Element type : SVector{2, ComplexF64}\n Nonzero elements : 7408","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Note that r is not of type Hamiltonian. The BarebonesOperator is a specially simple operator type that simply encodes a number of Bloch harmonics (matrices between different unit cells) of arbitrary element type. It supports only a subset of the funcitionality of AbstractHamiltonians. In particular, it supports indexing:","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> r[SA[0,0]]\n10×10 SparseArrays.SparseMatrixCSC{SVector{2, ComplexF64}, Int64} with 50 stored entries:\n [-0.000563148+0.0im, 1.79768+0.0im] … ⋅\n ⋅ [0.164126-2.15538e-5im, -0.000484848-0.0144407im]\n ⋅ [0.0195449-4.9251e-5im, 2.02798e-7+0.00140866im]\n [2.48859e-5-0.0185437im, -0.00534254-1.88085e-5im] ⋅\n ⋅ [2.07772e-7-0.00769914im, 0.00831306+1.45056e-5im]\n [-0.00340134-1.02057e-5im, 1.89607e-5+0.00656423im] … ⋅\n [-0.000371236+0.0227337im, -0.101768+1.64659e-5im] ⋅\n ⋅ [0.210672-5.77589e-5im, -0.000233323-0.00456068im]\n [0.164126-2.14909e-5im, -0.000483435-0.0144407im] ⋅\n ⋅ [0.000608652+0.0im, 2.12317+0.0im]\n\njulia> r[sites(1), sites(4)]\n2-element SVector{2, ComplexF64} with indices SOneTo(2):\n 2.4885857e-5 + 0.018543702im\n -0.0053425408 + 1.8808481e-5im","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"It is possible to modify the imported Wannier90 models using the full Quantica.jl machinery. For example, we can add any AbstractModel to the Wannier90 model upon import just by passing it as a second argument","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = EP.wannier90(\"wannier_tb.dat\", @onsite((; Δ = 0) -> Δ); dim = 2)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7560\n modifiers : 1\n\njulia> h = hamiltonian(w)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 10\n Hoppings : 7540\n Coordination : 754.0\n Parameters : [:Δ]","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Note that since we used a ParametricModel with a single parametric term, this introduced one modifier, since ParametricModels are simply an ordinary base model plus one modifier for each parametric term. As a result, h is now parametric.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"note: Adding models after import\nAlthough the above is the recommended way to add a Quantica model to a Wannier90 model (i.e. explicitly at import time), one can also do the same with Quantica.add!(EP.hbuilder(w), model) to modify w in place after its creation. This employs internal functionality, so it is not recommended, as it could change without warning.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"We can also use the following syntax apply one or more modifiers explicitly","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w´ = w |> @onsite!((o; k = 0) -> o + k)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7560\n modifiers : 2","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"An interesting application of modifiers is the addition of an electric field that couples to the full r operator. In an strict tight-binding limit, we would add an electric field E simply as an onsite potential","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> hE = h |> @onsite!((o, r; E = SA[0,0]) -> o + E'*r);","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"However, we actually have the full r operator now, which includes non-diagonal matrix elements. We can then incorporate the electric field term E'*r more precisely. We can do so using the --> syntax and the indexing functionality of the r::BarebonesOperator that we obtained from Wannier90","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> hE = h |> @onsite!((o, i; E = SA[0,0]) --> o + E'*r[i,i]) |> @hopping!((t, i, j; E = SA[0,0]) --> t + E'*r[i,j]);","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"note: Closures over non-constant objects\nNote that the above creates a closure over r, which is not const. As a result this would incur a small performance and allocation cost when evaluating hE(E=...). We can avoid it e.g. by defining r as a constant, const r = sites(w).","category":"page"},{"location":"tutorial/hamiltonians/#Hamiltonians","page":"Hamiltonians","title":"Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We build a Hamiltonian by combining a Lattice and a TightbindingModel, optionally specifying also the number of orbitals on each sublattice if there is more than one. A spinful graphene model (two orbitals per site in both sublattices) with nearest neighbor hopping t0 = 2.7 would be written as","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> lat = LP.honeycomb(); model = hopping(2.7*I);\n\njulia> h = hamiltonian(lat, model; orbitals = 2)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"A crucial thing to remember when defining multi-orbital Hamiltonians as the above is that onsite and hopping amplitudes need to be matrices of the correct size. The symbol I in Julia represents the identity matrix of any size, which is convenient to define a spin-preserving hopping in the case above. An alternative would be to use model = hopping(2.7*SA[1 0; 0 1]).","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Models with different number of orbitals per sublattice\nNon-homogeneous multiorbital models are more advanced but are fully supported in Quantica.jl. Just use orbitals = (n₁, n₂,...) to have nᵢ orbitals in sublattice i, and make sure your model is consistent with that. As in the case of the dim keyword in lattice, you can also use Val(nᵢ) for marginally faster construction.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Similarly to LatticePresets, we also have HamiltonianPresets, also aliased as HP. Currently, we have only HP.graphene(...) and HP.twisted_bilayer_graphene(...), but we expect to extend this library in the future (see the docstring of HP).","category":"page"},{"location":"tutorial/hamiltonians/#A-more-elaborate-example:-the-Kane-Mele-model","page":"Hamiltonians","title":"A more elaborate example: the Kane-Mele model","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The Kane-Mele model for graphene describes intrinsic spin-orbit coupling (SOC), in the form of an imaginary second-nearest-neighbor hopping between same-sublattice sites, with a sign that alternates depending on hop direction dr. A possible implementation in Quantica.jl would be","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"SOC(dr) = 0.05 * ifelse(iseven(round(Int, atan(dr[2], dr[1])/(pi/3))), im, -im)\n\nmodel =\n hopping(1, range = neighbors(1)) +\n hopping((r, dr) -> SOC(dr); sublats = :A => :A, range = neighbors(2)) +\n hopping((r, dr) -> -SOC(dr); sublats = :B => :B, range = neighbors(2))\n\nh = LatticePresets.honeycomb() |> model\n\nqplot(h)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"\"Kane-Mele","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Interactive tooltips in the visualization of h are enabled by default (use keyword inspector = false to disable them). They allows to navigate each onsite and hopping amplitude graphically. Note that sites connected to the unit cell of h by some hopping are included, but are rendered with partial transparency by default.","category":"page"},{"location":"tutorial/hamiltonians/#ParametricHamiltonians","page":"Hamiltonians","title":"ParametricHamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"If we use a ParametricModel instead of a simple TightBindingModel we will obtain a ParametricHamiltonian instead of a simple Hamiltonian, both of which are subtypes of the AbstractHamiltonian type","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> model_param = @hopping((; t = 2.7) -> t*I);\n\njulia> h_param = hamiltonian(lat, model_param; orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:t]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can also apply Modifiers by passing them as extra arguments to hamiltonian, which results again in a ParametricHamiltonian with the parametric modifiers applied","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> peierls! = @hopping!((t, r, dr; Bz = 0) -> t * cis(-Bz/2 * SA[-r[2], r[1]]' * dr));\n\njulia> h_param_mod = hamiltonian(lat, model_param, peierls!; orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:Bz, :t]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that SA[-r[2], r[1]] above is a 2D SVector, because since the embedding dimension is E = 2, both r and dr are also 2D SVectors.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can also apply modifiers to an already constructed AbstractHamiltonian. The following is equivalent to the above","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param_mod = hamiltonian(h_param, peierls!);","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Modifiers do not commute\nWe can add as many modifiers as we need by passing them as extra arguments to hamiltonian, and they will be applied sequentially, one by one. Beware, however, that modifiers do not necessarily commute, in the sense that the result will in general depend on their order.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can obtain a plain Hamiltonian from a ParametricHamiltonian by applying specific values to its parameters. To do so, simply use the call syntax with parameters as keyword arguments","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param_mod(Bz = 0.1, t = 1)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Syntax `lat |> model` and `h |> modifier\nThe common cases lat |> hamiltonian(model) (or hamiltonian(lat, model)) and h |> hamiltonian(modifier) (or hamiltonian(h, modifier)) can be also written as lat |> model and h |> modifier, respectively. Hence hamiltonian(lat, model, modifier) may be written as lat |> model |> modifier. This form however does not allow to specify the number of orbitals per sublattice (it will be one, the default).","category":"page"},{"location":"tutorial/hamiltonians/#Obtaining-actual-matrices","page":"Hamiltonians","title":"Obtaining actual matrices","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"For an L-dimensional h::AbstractHamiltonian (i.e. defined on a Lattice with L Bravais vectors), the Hamiltonian matrix between any unit cell with cell index n and another unit cell at n+dn (here known as a Hamiltonian \"harmonic\") is given by h[dn]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h[(1,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n ⋅ ⋅ 2.7+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.7+0.0im\n ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅\n\njulia> h[(0,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 2.7+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.7+0.0im\n 2.7+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 2.7+0.0im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Cell distance indices\nWe can use Tuples or SVectors for cell distance indices dn. An empty Tuple dn = () will always return the main intra-unitcell harmonic: h[()] = h[(0,0...)] = h[SA[0,0...]].","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"note: Bounded Hamiltonians\nIf the Hamiltonian has a bounded lattice (i.e. it has L=0 Bravais vectors), we will simply use an empty tuple to obtain its matrix h[()]. This is not in conflict with the above syntax.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that if h is a ParametricHamiltonian, such as h_param above, we will get zeros in place of the unspecified parametric terms, unless we actually first specify the values of the parameters","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param[(0,0)] # Parameter t is not specified -> it is not applied\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 0.0+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 0.0+0.0im ⋅ ⋅\n\njulia> h_param(t=2)[(0,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 2.0+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.0+0.0im\n 2.0+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 2.0+0.0im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"note: ParametricHamiltonian harmonics\nThe above behavior for unspecified parameters is not set in stone and may change in future versions. Another option would be to apply their default values (which may, however, not exist).","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We are usually not interested in the harmonics h[dn] themselves, but rather in the Bloch matrix of a Hamiltonian","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"H(phi) = sum_dn H_dn exp(-i phi * dn)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"where H_dn are the Hamiltonian harmonics, phi = (phi_1 phi_2) = (kcdot A_1 kcdot A_2) are the Bloch phases, k is the Bloch wavevector and A_i are the Bravais vectors.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We obtain the Bloch matrix using the syntax h(ϕ; params...)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h((0,0))\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 8.1+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 8.1+0.0im\n 8.1+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 8.1+0.0im ⋅ ⋅\n\njulia> h_param_mod((0.2, 0.3); B = 0.1)\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 7.92559-1.33431im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 7.92559-1.33431im\n 7.92559+1.33431im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 7.92559+1.33431im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that unspecified parameters take their default values when using the call syntax (as per the standard Julia convention). Any unspecified parameter that does not have a default value will produce an UndefKeywordError error.","category":"page"},{"location":"tutorial/hamiltonians/#Transforming-Hamiltonians","page":"Hamiltonians","title":"Transforming Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Like with lattices, we can transform an h::AbstractHamiltonians using supercell, reverse, transform and translate. All these except supercell operate only on the underlying lattice(h) of h, leaving the hoppings and onsite elements unchanged. Meanwhile, supercell acts on lattice(h) but also copies the hoppings and onsites of h onto the new sites, preserving the periodicity of the original h.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Additionally, we can also use torus, which makes the h lattice periodic along some (or all) of its Bravais vectors, while leaving the rest unbounded.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> torus(HP.graphene(), (0, :))\nHamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 4\n Coordination : 2.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The phases argument of torus(h, phases) is a Tuple of real numbers and/or colons (:), of length equal to the lattice dimension of h. Each real number ϕᵢ corresponds to a Bravais vector along which the transformed lattice will become periodic, picking up a phase exp(iϕᵢ) in the new hoppings, while each colon leaves the lattice unbounded along the corresponding Bravais vector. In a way torus is dual to supercell, in that it applies a different boundary condition to the lattice along the eliminated Bravais vectors, periodic instead of open, as in the case of supercell. The phases ϕᵢ are also connected to Bloch phases, in the sense that e.g. torus(h, (ϕ₁, :))(ϕ₂) == h(ϕ₁, ϕ₂)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Caveat of the Bloch-torus duality\nThe relation torus(h, phases)(()) = h(phases) is quite general. However, in some cases with position-dependent models, this may not hold. This may happen when some of the new hoppings added by torus are already present in h, as in cases with hoppings at ranges equal or larger than half the size of the unit cell.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"It's important to understand that, when transforming an h::AbstractHamiltonian, the model used to build h is not re-evaluated. Hoppings and onsite energies are merely copied so as to preserve the periodicity of the original h. As a consequence, these two constructions give different Hamiltonians","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1 = LP.linear() |> supercell(4) |> hamiltonian(onsite(r -> r[1]));\n\njulia> h2 = LP.linear() |> hamiltonian(onsite(r -> r[1])) |> supercell(4);","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"In the case of h1 the onsite model is applied to the 4-site unitcell. Since each site has a different position, each gets a different onsite energy.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im ⋅ ⋅ ⋅\n ⋅ 1.0+0.0im ⋅ ⋅\n ⋅ ⋅ 2.0+0.0im ⋅\n ⋅ ⋅ ⋅ 3.0+0.0im","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"In contrast h2 first gets the onsite model applied with a 1-site unitcell at position r = SA[0], so all sites in the lattice get onsite energy zero. Only then it is expanded with supercell, which generates a 4-site unitcell with zero onsite energy on all its sites","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h2[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im ⋅ ⋅ ⋅\n ⋅ 0.0+0.0im ⋅ ⋅\n ⋅ ⋅ 0.0+0.0im ⋅\n ⋅ ⋅ ⋅ 0.0+0.0im","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"As a consequence, h and supercell(h) represent exactly the same system, with the same observables, but with a different choice of unitcell.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"These two different behaviors make sense in different situations, so it is important to be aware of the order dependence of transformations. Similar considerations apply to transform, translate and torus when models are position dependent.","category":"page"},{"location":"tutorial/hamiltonians/#Combining-Hamiltonians","page":"Hamiltonians","title":"Combining Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Multiple h::AbstractHamiltonians (or multiple l::Lattices) can be combined into one with combine.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1 = LP.linear(dim = 2) |> hopping(1); h2 = LP.linear(dim = 2, names = :B) |> hopping(1) |> translate(SA[0,1]) |> @onsite!((o; p=1) -> o+p);\n\njulia> combine(h1, h2; coupling = hopping(2))\nParametricHamiltonian{Float64,2,1}: Parametric Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:p]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The coupling keyword, available when combining h::AbstractHamiltonians, is a hopping model that is applied between each h. It can be constrained as usual with hopselectors and also be parametric. If either coupling or any of the combined h is parametric, the result of combine will be a ParametricHamiltonian, or a Hamiltonian otherwise.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The objects to be combined must satisfy some conditions:","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"They must have the same Bravais vectors (modulo reorderings), which will be then inherited by the combined object.\nThey must have the same position type (the T in AbstractHamiltonian{T} and Lattice{T})\nThey must have no repeated sublattice names among them (unless the combined object is non-parametric)","category":"page"},{"location":"tutorial/tutorial/#Tutorial","page":"Welcome","title":"Tutorial","text":"","category":"section"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Welcome to the Quantica.jl tutorial!","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Here you will learn how to use Quantica.jl to build and compute properties of tight-binding models. This includes","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Defining general Lattices in arbitrary dimensions\nDefining generic tight-binding Models with arbitrary parameter dependences\nBuilding Hamiltonians of mono- or multiorbital systems by combining Lattices and Models\nComputing Bandstructures of Hamiltonians\nComputing GreenFunctions of Hamiltonians or OpenHamiltonians (i.e. Hamiltonians with attached self-energies from other Hamiltonians, such as leads).\nComputing Observables from Green functions, such as spectral densities, current densities, local and nonlocal conductances, Josephson currents, critical currents, transmission probabilities, etc.","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Check the menu on the left for shortcuts to the relevant sections.","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"tip: Check the docstrings\nFull usage instructions on all Quantica.jl functions can be found here or within the Julia REPL by querying their docstrings. For example, to obtain details on the hamiltonian function or on the available LatticePresets, just type ?hamiltonian or ?LatticePresets.","category":"page"},{"location":"advanced/serializers/#Serializers","page":"Serializers","title":"Serializers","text":"","category":"section"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"Serializers are useful to translate between a complex data structure and a stream of plain numbers of a given type. Serialization and deserialization is a common encode/decode operation in programming language.","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"In Quantica, a s::Serializer{T} is an object that takes an h::AbstractHamiltonian, a selection of the sites and hoppings to be translated, and an encoder/decoder pair of functions to translate each element into a portion of the stream. This s can then be used to convert the specified elements of h into a vector of scalars of type T and back, possibly after applying some parameter values. Consider this example from the serializer docstring","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"julia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);\n\njulia> as = serializer(Float64, h1; encoder = s -> reim(s), decoder = v -> complex(v[1], v[2]))\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : ParametricHamiltonian\n Object parameters : [:U]\n Stream parameter : :stream\n Output eltype : Float64\n Encoder/Decoder : Single\n Length : 6\n\njulia> v = serialize(as; U = 4)\n6-element Vector{Float64}:\n -4.0\n 0.0\n -0.0\n -1.0\n 0.0\n 1.0\n\njulia> h2 = deserialize!(as, v);\n\njulia> h2 == h1(U = 4)\ntrue\n\njulia> h3 = hamiltonian(as)\nParametricHamiltonian{Float64,1,1}: Parametric Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 1 × 1\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 1\n Hoppings : 2\n Coordination : 2.0\n Parameters : [:U, :stream]\n\njulia> h3(stream = v, U = 5) == h1(U = 4) # stream overwrites the U=5 onsite terms\ntrue","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"The serializer functionality is designed with efficiency in mind. Using the in-place serialize!/deserialize! pair we can do the encode/decode round trip without allocations","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"julia> using BenchmarkTools\n\njulia> v = Vector{Float64}(undef, length(as));\n\njulia> deserialize!(as, serialize!(v, as)) === Quantica.call!(h1, U = 4)\ntrue\n\njulia> @btime deserialize!($as, serialize!($v, $as));\n 149.737 ns (0 allocations: 0 bytes)","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"It also allows powerful compression into relevant degrees of freedom through appropriate use of encoders/decoders, see the serializer docstring.","category":"page"},{"location":"advanced/serializers/#Serializers-of-OrbitalSliceArrays","page":"Serializers","title":"Serializers of OrbitalSliceArrays","text":"","category":"section"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"Serialization of OrbitalSliceArrays is simpler than for AbstractHamiltonians, as there is no need for an intermediate Serializer object. To serialize an m::OrbitalSliceArray simply do v = serialize(m). To deserialize, just do m´ = deserialize(m, v).","category":"page"},{"location":"api/#api","page":"API","title":"API","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"CurrentModule = Quantica","category":"page"},{"location":"api/","page":"API","title":"API","text":"","category":"page"},{"location":"api/","page":"API","title":"API","text":"Modules = [Quantica]","category":"page"},{"location":"api/#Quantica.EigenSolvers","page":"API","title":"Quantica.EigenSolvers","text":"EigenSolvers is a Quantica submodule containing support for several pre-defined eigensolver extensions. The alias ES can be used in place of EigenSolvers. Currently supported solvers are\n\nES.LinearAlgebra(; kw...) # Uses `eigen(mat; kw...)` from the `LinearAlgebra` package\nES.Arpack(; kw...) # Uses `eigs(mat; kw...)` from the `Arpack` package (WARNING: Arpack is not thread-safe)\nES.KrylovKit(params...; kw...) # Uses `eigsolve(mat, params...; kw...)` from the `KrylovKit` package\nES.ArnoldiMethod(; kw...) # Uses `partialschur(mat; kw...)` from the `ArnoldiMethod` package.\n\nTo use each of these solvers the corresponding package must be loaded with e.g. using ArnoldiMethod. The exception is the default ES.LinearAlgebra which is a direct Quantica dependency and does not require loading.\n\nAdditionally, to compute interior eigenvalues, we can use a shift-invert method around energy ϵ0 (uses LinearMaps and a LinearAlgebra.lu factorization), combined with any solver s from the list above:\n\nES.ShiftInvert(s, ϵ0) # Perform a lu-based shift-invert with solver `s`\n\nThe ShiftInvert solver extension requires doing using LinearMaps.\n\nExamples\n\njulia> using LinearMaps, ArnoldiMethod # loads required extensions\n\njulia> h = HP.graphene(t0 = 1) |> supercell(10);\n\njulia> spectrum(h, (0,0); solver = ES.ShiftInvert(ES.ArnoldiMethod(nev = 4), 0.0)) |> energies\n4-element Vector{ComplexF64}:\n -0.3819660112501042 + 2.407681231060336e-16im\n -0.6180339887498942 - 2.7336317916863215e-16im\n 0.6180339887498937 - 1.7243387890744497e-16im\n 0.3819660112501042 - 1.083582785131051e-16im\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.ExternalPresets","page":"API","title":"Quantica.ExternalPresets","text":"ExternalPresets is a Quantica submodule containing utilities to import objects from external applications The alias EP can be used in place of ExternalPresets. Currently supported importers are\n\nEP.wannier90(args...; kw...)\n\nFor details on the arguments args and keyword arguments kw see the docstring for the corresponding function.\n\nSee also\n\n`LatticePresets`, `RegionPresets`, `HamiltonianPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.GreenSolvers","page":"API","title":"Quantica.GreenSolvers","text":"GreenSolvers is a Quantica submodule containing several pre-defined Green function solvers. The alias GS can be used in place of GS. Currently supported solvers and their possible keyword arguments are\n\nGS.SparseLU() : Direct inversion solver for 0D Hamiltonians using a SparseArrays.lu(hmat) factorization\nGS.Spectrum(; spectrum_kw...) : Diagonalization solver for 0D Hamiltonians using spectrum(h; spectrum_kw...)\nspectrum_kw... : keyword arguments passed on to spectrum\nThis solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first. Contact self-energies that depend on parameters are supported.\nGS.Schur(; boundary = Inf) : Solver for 1D Hamiltonians based on a deflated, generalized Schur factorization\nboundary : 1D cell index of a boundary cell, or Inf for no boundaries. Equivalent to removing that specific cell from the lattice when computing the Green function.\nGS.KPM(; order = 100, bandrange = missing, kernel = I) : Kernel polynomial method solver for 0D Hamiltonians\norder : order of the expansion in Chebyshev polynomials Tₙ(h) of the Hamiltonian h (lowest possible order is n = 0).\nbandrange : a (min_energy, max_energy)::Tuple interval that encompasses the full band of the Hamiltonian. If missing, it is computed automatically, but using ArnoldiMethod is required first.\nkernel : generalization that computes momenta as μₙ = Tr[Tₙ(h)*kernel], so that the local density of states (see ldos) becomes the density of the kernel operator.\nThis solver does not allow arbitrary indexing of the resulting g::GreenFunction, only on contacts g[contact_ind::Integer]. If the system has none, we can add a dummy contact using attach(h, nothing; sites...), see attach.\nGS.Bands(bands_arguments; boundary = missing, bands_kw...): solver based on the integration of bandstructure simplices\nbands_arguments: positional arguments passed on to bands\nbands_kw: keyword arguments passed on to bands\nboundary: either missing (no boundary), or dir => cell_pos (single boundary), where dir::Integer is the Bravais vector normal to the boundary, and cell_pos::Integer the value of cell indices cells[dir] that define the boundary (i.e. cells[dir] <= cell_pos are vaccum)\nThis solver only allows zero or one boundary. WARNING: if a boundary is used, the algorithm may become unstable for very fine band meshes.\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.HamiltonianPresets","page":"API","title":"Quantica.HamiltonianPresets","text":"HamiltonianPresets is a Quantica submodule containing several pre-defined Hamiltonians. The alias HP can be used in place of HamiltonianPresets. Currently supported hamiltonians are\n\nHP.graphene(; kw...)\nHP.twisted_bilayer_graphene(; kw...)\n\nFor details on the keyword arguments kw see the corresponding docstring\n\njulia> HamiltonianPresets.twisted_bilayer_graphene(twistindices = (30, 1))\nHamiltonian{Float64,3,2}: Hamiltonian on a 2D Lattice in 3D space\n Bloch harmonics : 7\n Harmonic size : 11164 × 11164\n Orbitals : [1, 1, 1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 315684\n Coordination : 28.27696\n\nSee also\n\n`LatticePresets`, `RegionPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.LatticePresets","page":"API","title":"Quantica.LatticePresets","text":"LatticePresets is a Quantica submodule containing several pre-defined lattices. The alias LP can be used in place of LatticePresets. Currently supported lattices are\n\nLP.linear(; a0 = 1, kw...) # linear lattice in 1D\nLP.square(; a0 = 1, kw...) # square lattice in 2D\nLP.triangular(; a0 = 1, kw...) # triangular lattice in 2D\nLP.honeycomb(; a0 = 1, kw...) # honeycomb lattice in 2D\nLP.cubic(; a0 = 1, kw...) # cubic lattice in 3D\nLP.fcc(; a0 = 1, kw...) # face-centered-cubic lattice in 3D\nLP.bcc(; a0 = 1, kw...) # body-centered-cubic lattice in 3D\nLP.hcp(; a0 = 1, kw...) # hexagonal-closed-packed lattice in 3D\n\nIn all cases a0 denotes the lattice constant, and kw... are extra keywords forwarded to lattice.\n\nExamples\n\njulia> LatticePresets.honeycomb(names = (:C, :D))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.5, 0.866025], [-0.5, 0.866025]]\n Sublattices : 2\n Names : (:C, :D)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> LatticePresets.cubic(bravais = ((1, 0), (0, 2)))\nLattice{Float64,3,2} : 2D lattice in 3D space\n Bravais vectors : [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell\n\nSee also\n\n`RegionPresets`, `HamiltonianPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.RegionPresets","page":"API","title":"Quantica.RegionPresets","text":"RegionPresets is a Quantica submodule containing several pre-defined regions of type Region{E}, where E is the space dimension. The alias RP can be used in place of RegionPresets. Supported regions are\n\nRP.circle(radius = 10, center = (0, 0)) # 2D\nRP.ellipse((rx, ry) = (10, 15), center = (0, 0)) # 2D\nRP.square(side = 10, center = (0, 0)) # 2D\nRP.rectangle((sx, sy) = (10, 15), center = (0, 0)) # 2D\nRP.sphere(radius = 10, center = (0, 0, 0)) # 3D\nRP.spheroid((rx, ry, rz) = (10, 15, 20), center = (0, 0, 0)) # 3D\nRP.cube(side = 10, center = (0, 0, 0)) # 3D\nRP.cuboid((sx, sy, sz) = (10, 15, 20), center = (0, 0, 0)) # 3D\n\nCalling a f::Region{E} object on a r::Tuple or r::SVector with f(r) or f(r...) returns true or false if r is inside the region or not. Note that only the first E coordinates of r will be checked. Arbitrary boolean functions can also be wrapped in Region{E} to create custom regions, e.g. f = Region{2}(r -> r[1]^2 < r[2]).\n\nBoolean combinations of Regions are supported using &, |, xor and ! operators, such as annulus = RP.circle(10) & !RP.circle(5).\n\nExamples\n\njulia> RegionPresets.circle(10)(20, 0, 0)\nfalse\n\njulia> RegionPresets.circle(10)(0, 0, 20)\ntrue\n\nSee also\n\n`LatticePresets`, `HamiltonianPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.zerofield","page":"API","title":"Quantica.zerofield","text":" zerofield\n\nAn sigleton of type ZeroField that represents a zero-valued field. It has the property that it returns zero no matter how it is indexed (zerofield[inds...] = 0.0 * I), so it is useful as a default value in a non-spatial model involving mean fields. See meanfield for a usage example.\n\nSee also\n\n`meanfield`\n\n\n\n\n\n","category":"constant"},{"location":"api/#Quantica.BoxIterator","page":"API","title":"Quantica.BoxIterator","text":"BoxIterator(seed::SVector{N,Int}; maxiterations = TOOMANYITERS)\n\nCartesian iterator iter over SVector{N,Int}s (cells) that starts at seed and grows outwards in the form of a box of increasing sides (not necesarily equal) until it encompasses a certain N-dimensional region. To signal that a cell is in the desired region the user calls acceptcell!(iter, cell).\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceArray","page":"API","title":"Quantica.OrbitalSliceArray","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceMatrix","page":"API","title":"Quantica.OrbitalSliceMatrix","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceVector","page":"API","title":"Quantica.OrbitalSliceVector","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Base.position","page":"API","title":"Base.position","text":"position(b::ExternalPresets.WannierBuilder)\n\nReturns the position operator in the Wannier basis. It is given as a r::BarebonesOperator object, which can be indexed as r[s, s´] to obtain matrix elements ⟨s|R|s´⟩ of the position operator R (a vector). Here s and s´ represent site indices, constructed with sites(cell, inds). To obtain the matrix between cells separated by dn::SVector{L,Int}, do r[dn]. The latter will throw an error if the dn harmonic is not present.\n\nSee also\n\n`current`, `sites`\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.reverse","page":"API","title":"Base.reverse","text":"reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})\n\nBuild a new lattice or hamiltonian with the orientation of all Bravais vectors and harmonics reversed.\n\nSee also\n\n`reverse!`, `transform`\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.reverse!","page":"API","title":"Base.reverse!","text":"reverse!(lat_or_h::Union{Lattice,AbstractHamiltonian})\n\nIn-place version of reverse, inverts all Bravais vectors and harmonics of lat_or_h.\n\nSee also\n\n`reverse`, `transform`\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.ishermitian","page":"API","title":"LinearAlgebra.ishermitian","text":"ishermitian(h::Hamiltonian)\n\nCheck whether h is Hermitian. This is not supported for h::ParametricHamiltonian, as the result can depend of the specific values of its parameters.\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.ExternalPresets.wannier90","page":"API","title":"Quantica.ExternalPresets.wannier90","text":"ExternalPresets.wannier90(filename::String; kw...)\n\nImport a Wannier90 tight-binding file in the form of a w::EP.WannierBuilder object. It can be used to obtain a Hamiltonian with hamiltonian(w), and the matrix of the position operator with sites(w).\n\nExternalPresets.wannier90(filename, model::AbstractModel; kw...)\n\nModify the WannierBuilder after import by adding model to it.\n\npush!(w::EP.WannierBuilder, modifier::AbstractModifier)\nw |> modifier\n\nApplies a modifier to w.\n\nKeywords\n\nhtol: skip matrix elements of the Hamiltonian smaller than this (in absolute value). Default: 1e-8\nrtol: skip non-diagonal matrix elements of the position operator smaller than this (in absolute value). Default: 1e-8\ndim: dimensionality of the embedding space for the Wannier orbitals, dropping trailing dimensions beyond dim if smaller than 3. Default: 3\nlatdim: dimensionality of the lattice, dropping trailing dimensions beyond latdim if smaller than 3. Should be latdim <= dim. Default: dim\ntype: override the real number type of the imported system. Default: Float64\n\nExamples\n\njulia> w = EP.wannier90(\"wannier_tb.dat\", @onsite((; o) -> o); htol = 1e-4, rtol = 1e-4, dim = 2, type = Float32)\nWannierBuilder{Float32,2,2} : 2-dimensional Hamiltonian builder from Wannier90 input, with positions of type Float32 in 2D-dimensional space\n cells : 151\n elements : 6724\n modifiers : 1\n\njulia> h = hamiltonian(w)\nParametricHamiltonian{Float32,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF32)\n Onsites : 10\n Hoppings : 6704\n Coordination : 670.4\n Parameters : [:o]\n\njulia> r = position(w)\nBarebonesOperator{2}: a simple collection of 2D Bloch harmonics\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Element type : SVector{2, ComplexF32}\n Nonzero elements : 7408\n\njulia> r[sites(SA[0,0], 3), sites(SA[1,0],2)]\n2-element SVector{2, ComplexF32} with indices SOneTo(2):\n -0.0016230071f0 - 0.00012927242f0im\n 0.008038711f0 + 0.004102786f0im\n\nSee also\n\n`hamiltonian`, `position`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.attach","page":"API","title":"Quantica.attach","text":"attach(h::AbstractHamiltonian, args..; sites...)\nattach(h::OpenHamiltonian, args...; sites...)\n\nBuild an h´::OpenHamiltonian by attaching (adding) a Σ::SelfEnergy to a finite number of sites in h specified by siteselector(; sites...). This also defines a \"contact\" on said sites that can be referred to (with index i::Integer for the i-th attached contact) when slicing Green functions later. Self-energies are taken into account when building the Green function g(ω) = (ω - h´ - Σ(ω))⁻¹ of the resulting h´, see greenfunction.\n\nSelf-energy forms\n\nThe different forms of args yield different types of self-energies Σ. Currently supported forms are:\n\nattach(h, gs::GreenSlice, coupling::AbstractModel; transform = missing, sites...)\n\nAdds a generic self-energy Σ(ω) = V´⋅gs(ω)⋅V on h's sites, where V and V´ are couplings (given by coupling) between said sites and the LatticeSlice in gs (after applying transform to the latter). Allowed forms of gs include both g[bath_sites...] and g[contactind::Integer] where g is any GreenFunction.\n\nattach(h, model::ParametricModel; sites...)\n\nAdd self-energy Σᵢⱼ(ω) defined by a model composed of parametric terms (@onsite and @hopping) with ω as first argument, as in e.g. @onsite((ω, r) -> Σᵢᵢ(ω, r)) and @hopping((ω, r, dr) -> Σᵢⱼ(ω, r, dr))\n\nattach(h, nothing; sites...)\n\nAdd a nothing contact with a null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to labeling those sites with a contact number, but does not lead to any dressing the Green function. This is useful for some GreenFunction solvers such as GS.KPM (see greenfunction), which need to know the sites of interest beforehand (the contact sites in this case).\n\nattach(h, g1D::GreenFunction; reverse = false, transform = identity, sites...)\n\nAdd a self-energy Σ(ω) = h₋₁⋅g1D(ω)[surface]⋅h₁ corresponding to a semi-infinite 1D lead (i.e. with a finite boundary, see greenfunction), where h₁ and h₋₁ are intercell couplings, and g1D is the lead GreenFunction. The g1D(ω) is taken at the suface unitcell, either adjacent to the boundary on its positive side (if reverse = false) or on its negative side (if reverse = true). Note that reverse only flips the direction we extend the lattice to form the lead, but does not flip the unit cell (may use transform for that) or any contacts in the lead. The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the left or right unit cell surface of the lead (i.e. sites coupled to the adjacent unit cells), after applying transform to the latter. If they don't match, use the attach syntax below.\n\nAdvanced: If the g1D does not have any self-energies, the produced self-energy is in fact an ExtendedSelfEnergy, which is numerically more stable than a naive implementation of RegularSelfEnergy's, since g1D(ω)[surface] is never actually computed. Conversely, if g1D has self-energies attached, a RegularSelfEnergy is produced.\n\nattach(h, g1D::GreenFunction, coupling::AbstractModel; reverse = false, transform = identity, sites...)\n\nAdd a self-energy Σ(ω) = V´⋅g1D(ω)[surface]⋅V corresponding to a 1D lead (semi-infinite or infinite), but with couplings V and V´, defined by coupling, between sites and the surface lead unitcell (or the one with index zero if there is no boundary) . See also Advanced note above.\n\nCurrying\n\nh |> attach(args...; sites...)\n\nCurried form equivalent to attach(h, args...; sites...).\n\nExamples\n\njulia> # A graphene flake with two out-of-plane cubic-lattice leads\n\njulia> g1D = LP.cubic(names = :C) |> hamiltonian(hopping(1)) |> supercell((0,0,1), region = RP.square(4)) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> coupling = hopping(1, range = 2);\n\njulia> gdisk = HP.graphene(a0 = 1, dim = 3) |> supercell(region = RP.circle(10)) |> attach(g1D, coupling; region = RP.square(4)) |> attach(g1D, coupling; region = RP.square(4), reverse = true) |> greenfunction;\n\nSee also\n\n`greenfunction`, `GreenSolvers`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.bands","page":"API","title":"Quantica.bands","text":"bands(h::AbstractHamiltonian, xcolᵢ...; kw...)\n\nConstruct a Bandstructure object, which contains in particular a collection of continuously connected Subbands of h, obtained by diagonalizing the matrix h(ϕs; params...) on an M-dimensional mesh of points (x₁, x₂, ..., xₘ), where each xᵢ takes values in the collection xcolᵢ. The mapping between points in the mesh points and values of (ϕs; params...) is defined by keyword mapping (identity by default, see Keywords). Diagonalization is multithreaded and will use all available Julia threads (start session with julia -t N to have N threads).\n\nbands(f::Function, xcolᵢ...; kw...)\n\nLike the above using f(ϕs)::AbstractMatrix in place of h(ϕs; params...), and returning a Vector{<:Subband} instead of a Bandstructure object. This is provided as a lower level driver without the added slicing functionality of a full Bandstructure object, see below.\n\nbands(h::AbstractHamiltonian; kw...)\n\nEquivalent to bands(h::AbstractHamiltonian, xcolᵢ...; kw...) with a default xcolᵢ = subdiv(-π, π, 49).\n\nKeywords\n\nsolver: eigensolver to use for each diagonalization (see Eigensolvers). Default: ES.LinearAlgebra()\nmapping: a function of the form (x, y, ...) -> ϕs or (x, y, ...) -> ftuple(ϕs...; params...) that translates points (x, y, ...) in the mesh to Bloch phases ϕs or phase+parameter FrankenTuples ftuple(ϕs...; params...). See also linecuts below. Default: identity\ntransform: function to apply to each eigenvalue after diagonalization. Default: identity\ndegtol::Real: maximum distance between to nearby eigenvalue so that they are classified as degenerate. Default: sqrt(eps)\nsplit::Bool: whether to split bands into disconnected subbands. Default: true\nprojectors::Bool: whether to compute interpolating subspaces in each simplex (for use as GreenSolver). Default: true\nwarn::Bool: whether to emit warning when band dislocations are encountered. Default: true\nshowprogress::Bool: whether to show or not a progress bar. Default: true\ndefects: (experimental) a collection of extra points to add to the mesh, typically the location of topological band defects such as Dirac points, so that interpolation avoids creating dislocation defects in the bands. You need to also increase patches to repair the subband dislocations using the added defect vertices. Default: ()\npatches::Integer: (experimental) if a dislocation is encountered, attempt to patch it by searching for the defect recursively to a given order, or using the provided defects (preferred). Default: 0\n\nCurrying\n\nh |> bands(xcolᵢ...; kw...)\n\nCurried form of bands equivalent to bands(h, xcolᵢ...; kw...)\n\nBand linecuts\n\nTo do a linecut of a bandstructure along a polygonal path in the L-dimensional Brillouin zone, mapping a set of 1D points xs to a set of nodes, with pts interpolation points in each segment, one can use the following convenient syntax\n\nbands(h, subdiv(xs, pts); mapping = (xs => nodes))\n\nHere nodes can be a collection of SVector{L} or of named Brillouin zone points from the list (:Γ,:K, :K´, :M, :X, :Y, :Z). If mapping = nodes, then xs defaults to 0:length(nodes)-1. See also subdiv for its alternative methods.\n\nIndexing and slicing\n\nb[i]\n\nExtract i-th subband from b::Bandstructure. i can also be a Vector, an AbstractRange or any other argument accepted by getindex(subbands::Vector, i)\n\nb[slice::Tuple]\n\nCompute a section of b::Bandstructure with a \"plane\" defined by slice = (ϕ₁, ϕ₂,..., ϕₗ[, ϵ]), where each ϕᵢ or ϵ can be a real number (representing a fixed momentum or energy) or a : (unconstrained along that dimension). For bands of an L-dimensional lattice, slice will be padded to an L+1-long tuple with : if necessary. The result is a collection of of sliced Subbands.\n\nExamples\n\njulia> phis = range(0, 2pi, length = 50); h = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t));\n\njulia> bands(h(t = 1), phis, phis)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 5000\n Edges : 14602\n Simplices : 9588\n\njulia> bands(h, phis, phis; mapping = (x, y) -> ftuple(0, x; t = y/2π))\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 4950\n Edges : 14553\n Simplices : 9604\n\njulia> bands(h(t = 1), subdiv((0, 2, 3), (20, 30)); mapping = (0, 2, 3) => (:Γ, :M, :K))\nBandstructure{Float64,2,1}: 2D Bandstructure over a 1-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 97\n Edges : 96\n Simplices : 96\n\nSee also\n\n`spectrum`, `subdiv`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.bravais_matrix","page":"API","title":"Quantica.bravais_matrix","text":"bravais_matrix(lat::Lattice)\nbravais_matrix(h::AbstractHamiltonian)\n\nReturn the Bravais matrix of lattice lat or AbstractHamiltonian h, with Bravais vectors as its columns.\n\nExamples\n\njulia> lat = lattice(sublat((0,0)), bravais = ((1.0, 2), (3, 4)));\n\njulia> bravais_matrix(lat)\n2×2 SMatrix{2, 2, Float64, 4} with indices SOneTo(2)×SOneTo(2):\n 1.0 3.0\n 2.0 4.0\n\n\nSee also\n\n`lattice`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.combine","page":"API","title":"Quantica.combine","text":"combine(lats::Lattice...)\n\nIf all lats have compatible Bravais vectors, combine them into a single lattice. If necessary, sublattice names are renamed to remain unique.\n\ncombine(hams::Hamiltonians...; coupling = TighbindingModel())\n\nCombine a collection hams of Hamiltonians into one by combining their corresponding lattices, and optionally by adding a coupling between them, given by the hopping terms in coupling.\n\nNote that the coupling model will be applied to the combined lattice (which may have renamed sublattices to avoid name collissions). However, only hopping terms between different hams blocks will be applied.\n\nLimitations\n\nCurrently, combine only works with Lattice{T} AbstractHamiltonians{T} with the same T. Furthermore, if any of the hams is a ParametricHamiltonian or coupling is a ParametricModel, the sublattice names of all hams must be distinct. This ensures that parametric models, which get applied through Modifiers after construction of the ParametricHamiltonian, are not applied to the wrong sublattice, since sublattice names could be renamed by combine if they are not unique. Therefore, be sure to choose unique sublattice names upon construction for all the hams to be combined (see lattice).\n\nExamples\n\njulia> # Building Bernal-stacked bilayer graphene\n\njulia> hbot = HP.graphene(a0 = 1, dim = 3, names = (:A,:B));\n\njulia> htop = translate(HP.graphene(a0 = 1, dim = 3, names = (:C,:D)), (0, 1/√3, 1/√3));\n\njulia> h2 = combine(hbot, htop; coupling = hopping(1, sublats = :B => :C) |> plusadjoint)\nHamiltonian{Float64,3,2}: Hamiltonian on a 2D Lattice in 3D space\n Bloch harmonics : 5\n Harmonic size : 4 × 4\n Orbitals : [1, 1, 1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 14\n Coordination : 3.5\n\nSee also\n\n`hopping`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.conductance","page":"API","title":"Quantica.conductance","text":"conductance(gs::GreenSlice; nambu = false)\n\nGiven a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object G::Conductance representing the zero-temperature, linear, differential conductance Gᵢⱼ = dIᵢ/dVⱼ between contacts i and j at arbitrary bias ω = eV in units of e^2/h. Gᵢⱼ is given by\n\n Gᵢⱼ = e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱ-gʳΓⁱgᵃΓʲ]} (nambu = false)\n Gᵢⱼ = e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱτₑ-gʳΓⁱτ₃gᵃΓʲτₑ]} (nambu = true)\n\nHere gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i. For Nambu systems (nambu = true), the matrices τₑ=[I 0; 0 0] and τ₃ = [I 0; 0 -I] ensure that charge reversal in Andreev reflections is properly taken into account. For normal systems (nambu = false), the total current at finite bias and temperatures is given by Iᵢ = eh dω ⱼ fᵢ(ω) - fⱼ(ω) Gᵢⱼ(ω), where fᵢ(ω) is the Fermi distribution in lead i.\n\nKeywords\n\nnambu : whether to consider the Hamiltonian of the system is written in a Nambu basis, each site containing N electron orbitals followed by N hole orbitals.\n\nFull evaluation\n\nG(ω; params...)\n\nCompute the conductance at the specified contacts.\n\nExamples\n\njulia> # A central system g0 with two 1D leads and transparent contacts\n\njulia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> G = conductance(g0[1])\nConductance{Float64}: Zero-temperature conductance dIᵢ/dVⱼ from contacts i,j, in units of e^2/h\n Current contact : 1\n Bias contact : 1\n\njulia> G(0.2) ≈ 3\ntrue\n\nSee also\n\n`greenfunction`, `ldos`, `current`, `josephson`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.current","page":"API","title":"Quantica.current","text":"current(h::AbstractHamiltonian; charge = -I, direction = 1)\n\nBuild an Operator object that behaves like a ParametricHamiltonian in regards to calls and getindex, but whose matrix elements are hoppings im*(rⱼ-rᵢ)direction*charge*tⱼᵢ, where tᵢⱼ are the hoppings in h. This operator is equal to hAᵢ, where Aᵢ is a gauge field along direction = i.\n\ncurrent(gs::GreenSlice; charge = -I, direction = missing)\n\nBuild Js::CurrentDensitySlice, a partially evaluated object representing the equilibrium local current density Jᵢⱼ(ω) at arbitrary energy ω from site j to site i, both taken from a specific lattice slice. The current is computed along a given direction (see Keywords).\n\ncurrent(gω::GreenSolution; charge = -I, direction = missing)\n\nBuild Jω::CurrentDensitySolution, as above, but for Jᵢⱼ(ω) at a fixed ω and arbitrary sites i, j. See also greenfunction for details on building a GreenSlice and GreenSolution.\n\nThe local current density is defined here as Jᵢⱼ(ω) = (2h) rᵢⱼ Re Tr(Hᵢⱼgⱼᵢ(ω) - gᵢⱼ(ω)Hⱼᵢ) * charge, with the integrated local current given by Jᵢⱼ = f(ω) Jᵢⱼ(ω) dω. Here Hᵢⱼ is the hopping from site j at rⱼ to i at rᵢ, rᵢⱼ = rᵢ - rⱼ, charge is the charge of carriers in orbital space (see Keywords), and gᵢⱼ(ω) is the retarded Green function between said sites.\n\nKeywords\n\ncharge : for multiorbital sites, charge can be a general matrix, which allows to compute arbitrary currents, such as spin currents.\ndirection: as defined above, Jᵢⱼ(ω) is a vector. If direction is missing the norm |Jᵢⱼ(ω)| is returned. If it is an u::Union{SVector,Tuple}, u⋅Jᵢⱼ(ω) is returned. If an n::Integer, Jᵢⱼ(ω)[n] is returned.\n\nFull evaluation\n\nJω[sites...]\nJs(ω; params...)\n\nGiven a partially evaluated Jω::CurrentDensitySolution or ρs::CurrentDensitySlice, build a sparse matrix Jᵢⱼ(ω) along the specified direction of fully evaluated local current densities.\n\nNote: Evaluating the current density returns a SparseMatrixCSC currently, instead of a OrbitalSliceMatrix, since the latter is designed for dense arrays.\n\nExample\n\njulia> # A semi-infinite 1D lead with a magnetic field `B`\n\njulia> g = LP.square() |> supercell((1,0), region = r->-2 hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> J = current(g[cells = SA[1]])\nCurrentDensitySlice{Float64} : current density at a fixed location and arbitrary energy\n charge : LinearAlgebra.UniformScaling{Int64}(-1)\n direction : missing\n\njulia> J(0.2; B = 0.1)\n3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n ⋅ 0.0290138 ⋅\n 0.0290138 ⋅ 0.0290138\n ⋅ 0.0290138 ⋅\n\njulia> J(0.2; B = 0.0)\n3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n ⋅ 7.77156e-16 ⋅\n 7.77156e-16 ⋅ 5.55112e-16\n ⋅ 5.55112e-16 ⋅\n\nSee also\n\n`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.decay_lengths","page":"API","title":"Quantica.decay_lengths","text":"Quantica.decay_lengths(g::GreenFunctionSchurLead, µ = 0; reverse = false)\nQuantica.decay_lengths(h::AbstractHamiltonian1D, µ = 0; reverse = false)\n\nCompute the decay lengths of evanescent modes of a 1D AbstractHamiltonian h or a 1D GreenFunction g using the GS.Schur solver. The modes decaying towards positive direction (relative to the Bravais vector) are used, unless reverse = true.\n\nExamples\n\njulia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));\n\njulia> Quantica.decay_lengths(h(U=2))\n1-element Vector{Float64}:\n 0.28364816427662776\n\nSee also:\n\n`Quantica.gaps`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.densitymatrix","page":"API","title":"Quantica.densitymatrix","text":"densitymatrix(gs::GreenSlice; opts...)\n\nCompute a ρ::DensityMatrix at thermal equilibrium on sites encoded in gs. The actual matrix for given system parameters params, and for a given chemical potential mu and temperature kBT is obtained by calling ρ(mu = 0, kBT = 0; params...). The algorithm used is specialized for the GreenSolver used, if available. In this case, opts are options for said algorithm.\n\ndensitymatrix(gs::GreenSlice, (ωmin, ωmax); opts..., quadgk_opts...)\ndensitymatrix(gs::GreenSlice, ωpoints; opts..., quadgk_opts...)\n\nAs above, but using a generic algorithm that relies on numerical integration along a contour in the complex plane, between points (ωmin, ωmax) (or along a polygonal path connecting ωpoints, a collection of numbers), which should be chosen so as to encompass the full system bandwidth. When the ωpoints are all real, an extra point is added at ω = µ to the integration path, to better integrate the step in the Fermi function. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine. See below for additiona opts.\n\ndensitymatrix(gs::GreenSlice, ωmax::Number; opts...)\n\nAs above with ωmin = -ωmax.\n\nFull evaluation\n\nρ(μ = 0, kBT = 0; params...) # where ρ::DensityMatrix\n\nEvaluate the density matrix at chemical potential μ and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any. The result is given as an OrbitalSliceMatrix, see its docstring for further details.\n\nIf the generic integration algorithm is used with complex ωpoints, the following form is also available:\n\nρ(μ = 0, kBT = 0, override_path = missing; params...)\n\nHere override can be a collection of ωpoints that will replace the original ones provided when defining ρ. Alternatively, it can be a function that will be applied to the original ωpoints. This may be useful when the integration path must depend on params.\n\nAlgorithms and keywords\n\nThe generic integration algorithm allows for the following opts (see also josephson):\n\nomegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.\nimshift: a small imaginary shift to add to the integration contour if all its vertices ωpoints are real numbers. Default: missing which is equivalent to sqrt(eps) for the relevant number type.\nslope: if ωpoints are all real numbers (typically encompassing the system's bandwidth), the integration contour is transformed into a triangular sawtooth path these points. Between each pair of points the path increases and then decreases linearly with the given slope. Default: 1.0.\npost: a function to apply to the result of the integration. Default: identity.\ncallback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand evaluated at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.\n\nThe quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.\n\nCurrently, the following GreenSolvers implement dedicated densitymatrix algorithms:\n\nGS.Schur: based on numerical integration over Bloch phase. Boundaries and non-empty contacts are not currently supported. Assumes Hermitian Hamiltonian. No opts.\nGS.Spectrum: based on summation occupation-weigthed eigenvectors. No opts.\nGS.KPM: based on the Chebyshev expansion of the Fermi function. Currently only works for zero temperature and only supports nothing contacts (see attach). No opts.\n\nExample\n\njulia> g = HP.graphene(a0 = 1) |> supercell(region = RP.circle(10)) |> greenfunction(GS.Spectrum());\n\njulia> ρ = densitymatrix(g[region = RP.circle(0.5)])\nDensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver\n\njulia> ρ() # with mu = kBT = 0 by default\n2×2 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.5+0.0im -0.262865+0.0im\n -0.262865+0.0im 0.5+0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.deserialize","page":"API","title":"Quantica.deserialize","text":"deserialize(as::AppliedSerializer, v; params...)\n\nConstruct h(; params...), where h = Quantica.parametric_hamiltonian(as) is the AbstractHamiltonian enclosed in as, with the matrix elements enconded in v = serialize(s) restored (i.e. overwritten). See serialize for details.\n\ndeserialize(m::OrbitalSliceArray, v)\n\nReconstruct an OrbitalSliceArray with the same structure as m but with the matrix elements enconded in v. This v is typically the result of a serialize call to a another similar m, but the only requirement is that is has the correct size. If v has the wrong eltype, it will be reintepreted to match the eltype of m.\n\nSee also\n\n`serializer`, `serialize`, `serialize!`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.deserialize!","page":"API","title":"Quantica.deserialize!","text":"deserialize!(as::AppliedSerializer, v; params...)\n\nIn-place version of deserialize. It returns h´ = Quantica.call!(h; params...) with serialised elements v restored (i.e. overwritten). Here h = Quantica.parent_hamiltonian(s) is the AbstractHamiltonian used to construct as. The resulting h´::Hamiltonian is not an independent copy, but is aliased with h.\n\nExamples\n\njulia> h = HP.graphene() |> supercell(2);\n\njulia> s = serializer(h)\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : Hamiltonian\n Object parameters : none\n Stream parameter : :stream\n Output eltype : ComplexF64\n Encoder/Decoder : Single\n Length : 24\n\njulia> h === deserialize!(s, serialize(s))\ntrue\n\njulia> h === deserialize(s, serialize(s))\nfalse\n\njulia> h == deserialize(s, serialize(s))\ntrue\n\nSee also\n\n`serializer`, `serialize`, `serialize!`, `deserialize`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.diagonal","page":"API","title":"Quantica.diagonal","text":"diagonal(i; kernel = missing)\n\nWrapper over site or orbital indices i (used to index into a g::GreenFunction or g::GreenSolution) that represent purely diagonal entries. Here i can be any index accepted in g[i,i], e.g. i::Integer (contact index), i::Colon (merged contacts), i::SiteSelector (selected sites), etc.\n\nIf kernel = Q (a matrix) instead of missing, each diagonal block for multiorbital site i is replaced with Tr(gᵢᵢQ).\n\nFor a gω::GreenSolution, gω[diagonal(sel)] = diag(gω[sel, sel]), although where possible the former computation is done more efficiently internally.\n\ndiagonal(; kernel = missing, sites...)\n\nEquivalent to diagonal(siteselector(; sites...); kernel)\n\nKeywords\n\n- `kernel`: if missing, all orbitals in the diagonal `g[i, i]` are returned when indexing `g[diagonal(i)]`. Otherwise, `Tr(g[site, site]*kernel)` for each site included in `i` is returned.\n\nExample\n\njulia> g = HP.graphene(orbitals = 2) |> attach(nothing, cells = (0,0)) |> greenfunction();\n\njulia> g(1)[diagonal(:)] # g(ω = 1) diagonal on all contact orbitals\n4×4 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:\n -0.10919-0.0839858im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im -0.10919-0.0839858im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im -0.10919-0.0839858im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im -0.10919-0.0839858im\n\njulia> g(1)[diagonal(:, kernel = SA[1 0; 0 -1])] # σz spin density of the above\n2×2 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:\n 5.61885e-12+1.38778e-17im 0.0+0.0im\n 0.0+0.0im -5.61882e-12+2.77556e-17im\n\nSee also\n\n`sitepairs`, `greenfunction`, `ldos`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.energies","page":"API","title":"Quantica.energies","text":"energies(sp::Spectrum)\n\nReturns the energies in sp as a vector of Numbers (not necessarily real). Equivalent to first(sp).\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.gap","page":"API","title":"Quantica.gap","text":"Quantica.gap(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)\n\nCompute the minimal gap around µ, see Quantica.gaps\n\nSee also:\n\n`Quantica.gaps`, `Quantica.decay_lengths`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.gaps","page":"API","title":"Quantica.gaps","text":"Quantica.gaps(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)\n\nCompute the energy gaps of a 1D Hamiltonian h at chemical potential µ. The result is a Vector{T} of the local minima of the |ϵ(ϕ) - µ|, where ϵ(ϕ) is the energy band closest to µ and ϕ ∈ [-π,π] is the Bloch phase. The atol parameter is the absolute tolerance used to determine the local minima versus ϕ, which are computed using the Schur solver for 1D Hamiltonians. The keywords kw are passed to the ArnoldiMethod partialschur! eigensolver (kw = (; nev = 1) by default).\n\nThe LinearMaps and ArnoldiMethod packages must be loaded to enable this functionality.\n\nExamples\n\njulia> using LinearMaps, ArnoldiMethod\n\njulia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));\n\njulia> Quantica.gaps(h(U=2))\n2-element Vector{Float64}:\n 1.9999999999999996\n 1.9999999999999991\n\nSee also:\n\n`Quantica.gap`, `Quantica.decay_lengths`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.greenfunction","page":"API","title":"Quantica.greenfunction","text":"greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::AbstractGreenSolver)\n\nBuild a g::GreenFunction of Hamiltonian h using solver. See GreenSolvers for available solvers. If solver is not provided, a default solver is chosen automatically based on the type of h.\n\nCurrying\n\nh |> greenfunction(solver)\n\nCurried form equivalent to greenfunction(h, solver).\n\nPartial evaluation\n\nGreenFunctions allow independent, partial evaluation of their positions (producing a GreenSlice) and energy/parameters (producing a GreenSolution). Depending on the solver, this may avoid repeating calculations unnecesarily when sweeping over either of these with the other fixed.\n\ng[ss]\ng[siteselector(; ss...)]\n\nBuild a gs::GreenSlice that represents a Green function at arbitrary energy and parameter values, but at specific sites on the lattice defined by siteselector(; ss...), with ss::NamedTuple (see siteselector).\n\ng[contact_index::Integer]\n\nBuild a GreenSlice equivalent to g[contact_sites...], where contact_sites... correspond to sites in contact number contact_index (must have 1<= contact_index <= number_of_contacts). See attach for details on attaching contacts to a Hamiltonian.\n\ng[:]\n\nBuild a GreenSlice over all contacts.\n\ng[dst, src]\n\nBuild a gs::GreenSlice between sites specified by src and dst, which can take any of the forms above. Therefore, all the previous single-index slice forms correspond to a diagonal block g[i, i].\n\ng[diagonal(i; kernel = missing)]\n\nBuild a diagonal gs::GreenSlice over sites specified by i. If kernel = missing the diagonal entries are g[o, o] for orbitals o in sites encoded in i. If kernel is a matrix, the diagonal elements are tr(g[site, site] * kernel) over each site i. Note that if there are several orbitals per site, g[site, site] may have different sizes (i.e. number of orbitals vs number of sites). Upon evaluating gs(ω), the result is a Diagonal matrix wrapped in an OrbitalSliceMatrix, and spans full unit cells.See also diagonal.\n\ng[sitepairs(; kernel = missing, hops...)]\n\nLike the above but for a selection of site pairs selected by hopselector(; hops...). Upon evaluating gs(ω), the result is a SparseMatrixCSC wrapped in an OrbitalSliceMatrix, and spans full unit cells. See also sitepairs.\n\ng(ω; params...)\n\nBuild a gω::GreenSolution that represents a retarded Green function at arbitrary points on the lattice, but at fixed energy ω and system parameter values param. If ω is complex, the retarded or advanced Green function is returned, depending on sign(imag(ω)). If ω is Real, a small, positive imaginary part is automatically added internally to produce the retarded g.\n\ngω[i]\ngω[i, j]\ngs(ω; params...)\n\nFor any gω::GreenSolution or gs::GreenSlice, build the Green function matrix fully evaluated at fixed energy, parameters and positions. The matrix is a dense m::OrbitalSliceMatrix with scalar element type, so that any orbital structure on each site is flattened. Note that the resulting m can itself be indexed over collections of sites with m[i, j], where i, j are siteselector(; ss...) or ss::NamedTuple.\n\nview(gω, i::C, j::C == i)\n\nFor any gω::GreenSolution and C<:Union{Colon,Integer}, obtain a view (of type SubArray, not OrbitalSliceMatrix) of the corresponding intra or inter-contact propagator gω[i, j] with minimal allocations.\n\ng(; params...)\n\nFor any g::Union{GreenFunction,GreenSlice}, produce a new GreenFunction or GreenSlice with all parameters fixed to params (or to their default values if not provided).\n\nFull evaluation\n\ngs(ω; params...)\ngω[sites...]\n\nFor gs::GreenSlice or gω::GreenSolution, return a fully evaluated m::AbstractMatrix. If the selected site slice was defined using sites, the concrete type of m will be will be a conventional Matrix-based type. Otherwise, it will be of type OrbitalSliceMatrix, an AbstractMatrix type that supports both conventional indexing and indexing with sites and siteselectors.\n\nAdvanced: in addition to the above, an unexported method Quantica.call!(gs, ω; params...) is provided to reuse the output matrix m (preallocated inside gs). Use with caution, as it may lead to unexpected aliasing\n\nExample\n\njulia> g = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t)) |> supercell(region = RP.circle(10)) |> greenfunction(GS.SparseLU())\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n ParametricHamiltonian{Float64,2,0}: Parametric Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 726 × 726\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 2098\n Coordination : 2.88981\n Parameters : [:t]\n\njulia> gω = g(0.1; t = 2)\nGreenSolution{Float64,2,0}: Green function at arbitrary positions, but at a fixed energy\n\njulia> ss = (; region = RP.circle(2), sublats = :B);\n\njulia> gs = g[ss]\nGreenSlice{Float64,2,0}: Green function at arbitrary energy, but at a fixed lattice positions\n\njulia> gω[ss] == gs(0.1; t = 2)\ntrue\n\njulia> summary(gω[ss])\n\"14×14 OrbitalSliceMatrix{ComplexF64,Array}\"\n\nSee also\n\n`GreenSolvers`, `diagonal`, `sitepairs`, `ldos`, `conductance`, `current`, `josephson`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hamiltonian","page":"API","title":"Quantica.hamiltonian","text":"hamiltonian(lat::Lattice, model; orbitals = 1)\n\nCreate an AbstractHamiltonian (i.e. an Hamiltonian or ParametricHamiltonian) by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building parametric and non-parametric tight-binding models).\n\nhamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)\n\nCreate a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided parametric modifiers (see @onsite! and @hopping! for details on defining modifiers).\n\nhamiltonian(h::AbstractHamiltonian, modifier, modifiers...)\n\nAdd modifiers to an existing AbstractHamiltonian.\n\nhamiltonian(h::ParametricHamiltonian)\n\nReturn the base (non-parametric) Hamiltonian of h, with all modifiers and parametric model terms removed (see @onsite, @hopping, @onsite!, @hopping!).\n\nKeywords\n\norbitals: number of orbitals per sublattice. If an Integer (or a Val{<:Integer} for type-stability), all sublattices will have the same number of orbitals. A collection of values indicates the orbitals on each sublattice.\n\nCurrying\n\nlat |> hamiltonian(model[, modifiers...]; kw...)\n\nCurried form of hamiltonian equivalent to hamiltonian(lat, model, modifiers...; kw...).\n\nlat |> model\n\nAlternative and less general curried form equivalent to hamiltonian(lat, model).\n\nh |> modifier\n\nAlternative and less general curried form equivalent to hamiltonian(h, modifier).\n\nIndexing\n\nh[dn::SVector{L,Int}]\nh[dn::NTuple{L,Int}]\n\nReturn the Bloch harmonic of an h::AbstractHamiltonian in the form of a SparseMatrixCSC with complex scalar eltype. This matrix is \"flat\", in the sense that it contains matrix elements between individual orbitals, not sites. This distinction is only relevant for multiorbital Hamiltonians. To access the non-flattened matrix use h[unflat(dn)] (see also unflat).\n\nh[()]\n\nSpecial syntax equivalent to h[(0...)], which access the fundamental Bloch harmonic.\n\nh[i::CellSites, j::CellSites = i]\n\nWith i and j of type CellSites and constructed with sites([cell,] indices), return a SparseMatrixCSC block of h between the sites with the corresponding indices and in the given cells. Alternatively, one can also use view(h, i, j = i), which should be non-allocating for AbstractHamiltonians with uniform number of orbitals.\n\nh[srow::SiteSelector, scol::SiteSelector = srow]\nh[kwrow::NamedTuple, kwcol::NamedTuple = kwrow]\n\nReturn an OrbitalSliceMatrix of h between row and column sites selected by srow and scol, or by siteselector(; kwrow...) and siteselector(; kwcol...)\n\nNote: CellSites and SiteSelectors can be mixed when indexing, in which case the matrix block will be returned as a SparseMatrixCSC, instead of an OrbitalSliceMatrix.\n\nCall syntax\n\nph(; params...)\n\nReturn a h::Hamiltonian from a ph::ParametricHamiltonian by applying specific values to its parameters params. If ph is a non-parametric Hamiltonian instead, this is a no-op.\n\nh(φs; params...)\n\nReturn the flat, sparse Bloch matrix of h::AbstractHamiltonian at Bloch phases φs, with applied parameters params if h is a ParametricHamiltonian. The Bloch matrix is defined as\n\n H = ∑_dn exp(-im φs⋅dn) H_dn\n\nwhere H_dn = h[dn] is the dn flat Bloch harmonic of h, and φs[i] = k⋅aᵢ in terms of the wavevector k and the Bravais vectors aᵢ.\n\nExamples\n\njulia> h = hamiltonian(LP.honeycomb(), hopping(SA[0 1; 1 0], range = 1/√3), orbitals = 2)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> h((0,0))\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 0.0+0.0im 3.0+0.0im\n ⋅ ⋅ 3.0+0.0im 0.0+0.0im\n 0.0+0.0im 3.0+0.0im ⋅ ⋅\n 3.0+0.0im 0.0+0.0im ⋅ ⋅\n\njulia> h[sites(1), sites(2)]\n2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im 1.0+0.0im\n 1.0+0.0im 0.0+0.0im\n\njulia> ph = h |> @hopping!((t; p = 3) -> p*t); ph[region = RP.square(1)]\n4×4 OrbitalSliceMatrix{ComplexF64,SparseMatrixCSC}:\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 3.0+0.0im\n 0.0+0.0im 0.0+0.0im 3.0+0.0im 0.0+0.0im\n 0.0+0.0im 3.0+0.0im 0.0+0.0im 0.0+0.0im\n 3.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n\nSee also\n\n`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`, `OrbitalSliceMatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hopping","page":"API","title":"Quantica.hopping","text":"hopping(t; hops...)\nhopping((r, dr) -> t(r, dr); hops...)\n\nBuild a TighbindingModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce an Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nhopping(m::Union{TighbindingModel,ParametricModel}; hops...)\n\nConvert m into a new model with just hopping terms acting on hops.\n\nModel algebra\n\nModels can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.\n\nExamples\n\njulia> model = hopping((r, dr) -> cis(dot(SA[r[2], -r[1]], dr)); dcells = (0,0)) + onsite(r -> rand())\nTightbindingModel: model with 2 terms\n HoppingTerm{Function}:\n Region : any\n Sublattice pairs : any\n Cell distances : (0, 0)\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n OnsiteTerm{Function}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 8 × 8\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 8\n Hoppings : 16\n Coordination : 2.0\n\nSee also\n\n`onsite`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`, `plusadjoint`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hopselector","page":"API","title":"Quantica.hopselector","text":"hopselector(; range = neighbors(1), dcells = missing, sublats = missing, region = missing)\n\nReturn a HopSelector object that can be used to select a finite set of hops between sites in a lattice. Hops between two sites at positions r₁ = r - dr/2 and r₂ = r + dr, belonging to unit cells with a cell distance dn::SVector{L,Int} and to a sublattices with names s₁::Symbol and s₂::Symbol will be selected only if\n\n`region(r, dr) && (s₁ => s₂ in sublats) && (dcell in dcells) && (norm(dr) <= range)`\n\nIf any of these is missing it will not be used to constraint the selection.\n\nGeneralization\n\nWhile range is usually a Real, and sublats and dcells are usually collections of Pair{Symbol}s and SVectors, respectively, they also admit other possibilities:\n\nsublats = :A # Hops from :A to :A\nsublats = :A => :B # Hops from :A to :B sublattices, but not from :B to :A\nsublats = (:A => :B,) # Same as above\nsublats = (:A => :B, :C => :D) # Hopping from :A to :B or :C to :D\nsublats = (:A, :C) .=> (:B, :D) # Broadcasted pairs, same as above\nsublats = (:A, :C) => (:B, :D) # Direct product, (:A=>:B, :A=>:D, :C=>:B, :C=>D)\nsublats = 1 => 2 # Hops from 1st to 2nd sublat. All the above patterns also admit Ints\nsublats = (spec₁, spec₂, ...) # Hops matching any of the specs with any of the above forms\n\ndcells = dn::SVector{L,Integer} # Hops between cells separated by `dn`\ndcells = dn::NTuple{L,Integer} # Hops between cells separated by `SVector(dn)`\ndcells = f::Function # Hops between cells separated by `dn` such that `f(dn) == true`\n\nrange = neighbors(n) # Hops within the `n`-th nearest neighbor distance in the lattice\nrange = (min, max) # Hops at distance inside the `[min, max]` closed interval (bounds can also be `neighbors(n)`)\n\nUsage\n\nAlthough the constructor hopselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering hops, which themselves call hopselector internally as needed. Some of these functions are\n\n- hopping(...; kw...) : hopping model term to be applied to site pairs specified by `kw`\n- @hopping(...; kw...) : parametric hopping model term to be applied to site pairs specified by `kw`\n- @hopping!(...; kw...) : hopping modifier to be applied to site pairs specified by `kw`\n\nExamples\n\njulia> h = LP.honeycomb() |> hamiltonian(hopping(1, range = neighbors(2), sublats = (:A, :B) .=> (:A, :B)))\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 7\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 12\n Coordination : 6.0\n\njulia> h = LP.honeycomb() |> hamiltonian(hopping(1, range = (neighbors(2), neighbors(3)), sublats = (:A, :B) => (:A, :B)))\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 9\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 18\n Coordination : 9.0\n\nSee also\n\n`siteselector`, `lattice`, `hopping`, `@hopping`, `@hopping!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.integrand","page":"API","title":"Quantica.integrand","text":"Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0)\n\nReturn the complex integrand d::JosephsonIntegrand whose integral over frequency yields the Josephson current, J(kBT) = post(∫dω d(ω)), with post = real. To evaluate the d for a given ω and parameters, use d(ω; params...), or call!(d, ω; params...) for its mutating (non-allocating) version.\n\nQuantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0)\n\nLike above for the density matrix ρ(mu, kBT), with d::DensityMatrixIntegrand and post = Quantica.gf_to_rho! that computes -(GF-GF')/(2π*im) in place for a matrix GF.\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.josephson","page":"API","title":"Quantica.josephson","text":"josephson(gs::GreenSlice, ωpoints; opts..., quadgk_opts...)\n\nFor a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a J::Josephson object representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated along a polygonal contour connecting ωpoints (a collection of numbers) in the complex plane. When the ωpoints are all real, an extra point is added at ω = 0 to the integration path, to better integrate the step in the Fermi function.\n\nThe result of I_J is given in units of qe/h (q is the dimensionless carrier charge). I_J can be written as I_J = Re dω f(ω) j(ω), where j(ω) = (qeh) 2Tr(ΣʳᵢGʳ - GʳΣʳᵢ)τz. Here f(ω) is the Fermi function with µ = 0.\n\njosephson(gs::GreenSlice, ωmax::Real; kw...)\n\nAs above, but with ωpoints = (-ωmax, ωmax).\n\nFull evaluation\n\nJ(kBT = 0, override_path = missing; params...) # where J::Josephson\n\nEvaluate the current I_J at chemical potemtial µ = 0 and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any.\n\nIt's possible to use override_path to override a complex integration path at evaluation time. In this case override_path can be a collection of ωpoints that will replace the original ones provided when defining J. Alternatively, it can be a function that will be applied to the original ωpoints. This may be useful when the integration path must depend on params.\n\nKeywords\n\nThe generic integration algorithm allows for the following opts (see also densitymatrix):\n\nomegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.\nphases : collection of superconducting phase biases to apply to the contact, so as to efficiently compute the full current-phase relation [I_J(ϕ) for ϕ in phases]. Note that each phase bias ϕ is applied by a [cis(-ϕ/2)*I 0*I; 0*I cis(ϕ/2)*I] rotation to the self energy, which is almost free. If missing, a single I_J is returned.\nimshift: a small imaginary shift to add to the integration contour if all its vertices ωpoints are real numbers. Default: missing which is equivalent to sqrt(eps) for the relevant number type.\nslope: if ωpoints, are all real numbers (typically encompassing the system's bandwidth), the integration contour is transformed into a triangular sawtooth path these points. Between each pair of points the path increases and then decreases linearly with the given slope. Default: 1.0.\npost: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.\ncallback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.\n\nThe quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.\n\nNote on analyticity\n\nA non-zero slope parameter (as is the default) moves the integration path into the upper-half complex-ω plane for increased performance. For this to work it's necessary that the Green function and it's attached self-energies all be analytic in the upper half-plane of complex ω. (Technically things will work also with independent analyticity in the upper-left and upper-right quarter-planes, since the path passes 0 by default). However, no check of analyticity is performed, so it is up to the user to ensure that. If this is not possible, consider using slope = 0, or choosing a set of ωpoints that avoids non-analyticities and cuts.\n\nExamples\n\njulia> glead = LP.square() |> hamiltonian(@onsite((; ω = 0) -> 0.0005 * SA[0 1; 1 0] + im*ω*I) + hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> J = josephson(g0[1], 4; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))\nJosephson: equilibrium Josephson current at a specific contact using solver of type JosephsonIntegratorSolver\n\njulia> J(0.0)\n10-element Vector{Float64}:\n 7.060440509787806e-18\n 0.0008178484258721882\n 0.0016108816082772972\n 0.002355033150366814\n 0.0030277117620820513\n 0.003608482493380227\n 0.004079679643085058\n 0.004426918320990192\n 0.004639358112465513\n 2.2618383948099795e-12\n\nSee also\n\n`greenfunction`,`ldos`, `current`, `conductance`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.lattice","page":"API","title":"Quantica.lattice","text":"lattice(sublats::Sublat...; bravais = (), dim, type, names)\nlattice(sublats::AbstractVector{<:Sublat}; bravais = (), dim, type, names)\n\nCreate a Lattice{T,E,L} from sublattices sublats, where L is the number of Bravais vectors given by bravais, T = type is the AbstractFloat type of spatial site coordinates, and dim = E is the spatial embedding dimension.\n\nlattice(lat::Lattice; bravais = missing, dim = missing, type = missing, names = missing)\n\nCreate a new lattice by applying any non-missing keywords to lat.\n\nlattice(x)\n\nReturn the parent lattice of object x, of type e.g. LatticeSlice, Hamiltonian, etc.\n\nKeywords\n\nbravais: a collection of one or more Bravais vectors of type NTuple{E} or SVector{E}. It can also be an AbstractMatrix of dimension E×L. The default bravais = () corresponds to a bounded lattice with no Bravais vectors.\nnames: a collection of Symbols. Can be used to rename sublats. Any repeated names will be replaced if necessary by :A, :B etc. to ensure that all sublattice names are unique.\n\nIndexing\n\nlat[kw...]\nlat[siteselector(; kw...)]\n\nIndexing into a lattice lat with keywords returns LatticeSlice representing a finite collection of sites selected by siteselector(; kw...). See siteselector for details on possible kw, and sites to obtain site positions.\n\nlat[]\n\nSpecial case equivalent to lat[cells = (0,...)] that returns a LatticeSlice of the zero-th unitcell.\n\nlat[i::CellSites]\n\nWith an i of type CellSites contructed with sites([cell,] indices), return a LatticeSlice of the corresponding sites.\n\nExamples\n\njulia> lat = lattice(sublat((0, 0)), sublat((0, 1)); bravais = (1, 0), type = Float32, dim = 3, names = (:up, :down))\nLattice{Float32,3,1} : 1D lattice in 3D space\n Bravais vectors : Vector{Float32}[[1.0, 0.0, 0.0]]\n Sublattices : 2\n Names : (:up, :down)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> lattice(lat; type = Float64, names = (:A, :B), dim = 2)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 0.0]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell\n\nSee also\n\n`LatticePresets`, `sublat`, `sites`, `supercell`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.ldos","page":"API","title":"Quantica.ldos","text":"ldos(gs::GreenSlice; kernel = missing)\n\nBuild ρs::LocalSpectralDensitySlice, a partially evaluated object representing the local density of states ρᵢ(ω) at specific sites i but at arbitrary energy ω.\n\nldos(gω::GreenSolution; kernel = missing)\n\nBuild ρω::LocalSpectralDensitySolution, as above, but for ρᵢ(ω) at a fixed ω and arbitrary sites i. See also greenfunction for details on building a GreenSlice and GreenSolution.\n\nThe local density of states is defined here as ρᵢ(ω) = -Tr(gᵢᵢ(ω))π, where gᵢᵢ(ω) is the retarded Green function at a given site i.\n\nKeywords\n\nkernel : for multiorbital sites, kernel allows to compute a generalized ldos ρᵢ(ω) = -imag(Tr(gᵢᵢ(ω) * kernel))/π, where gᵢᵢ(ω) is the retarded Green function at site i and energy ω. If kernel = missing, the complete, orbital-resolved ldos is returned. Default: missing\n\nFull evaluation\n\nρω[sites...]\nρs(ω; params...)\n\nGiven a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build an OrbitalSliceVector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states. See OrbitalSliceVector for further details.\n\nExample\n\njulia> g = HP.graphene(a0 = 1, t0 = 1) |> supercell(region = RP.circle(20)) |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 300, bandrange = (-3.1, 3.1)))\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedKPMGreenSolver\n Contacts : 1\n Contact solvers : (SelfEnergyEmptySolver,)\n Contact sizes : (6,)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 2898 × 2898\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 8522\n Coordination : 2.94065\n\njulia> ldos(g(0.2))[1]\n6-element OrbitalSliceVector{Vector{Float64}}:\n 0.036802204179316955\n 0.034933055722650375\n 0.03493305572265026\n 0.03493305572265034\n 0.03493305572265045\n 0.036802204179317045\n\njulia> ldos(g(0.2))[1] == -imag.(diag(g[diagonal(1)](0.2))) ./ π\ntrue\n\nSee also\n\n`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`, `OrbitalSliceVector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.meanfield","page":"API","title":"Quantica.meanfield","text":"meanfield(g::GreenFunction, args...; kw...)\n\nBuild a M::MeanField object that can be used to compute the Hartree-Fock-Bogoliubov mean field Φ between selected sites interacting through a given charge-charge potential. The density matrix used to build the mean field is obtained with densitymatrix(g[pair_selection], args...; kw...), see densitymatrix for details.\n\nThe mean field between site i and j is defined as Φᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ, where\n\nhartreeᵢ = ν * Q * Σ_k v_H(r_i-r_k) * tr(ρ[k,k]*Q)\nfockᵢⱼ = -v_F(r_i-r_j) * Q * ρ[i,j] * Q\n\nHere Q is the charge operator, v_H and v_F are Hartree and Fock interaction potentials, and ρ is the density matrix evaluated at specific chemical potential and temperature. Also ν = ifelse(nambu, 0.5, 1.0), and v_F(0) = v_H(0) = U, where U is the onsite interaction.\n\nKeywords\n\npotential: charge-charge potential to use for both Hartree and Fock. Can be a number or a function of position. Default: 1\nhartree: charge-charge potential v_H for the Hartree mean field. Can be a number or a function of position. Overrides potential. Default: potential\nfock: charge-charge potential v_F for the Fock mean field. Can be a number, a function of position or nothing. In the latter case all Fock terms (even onsite) will be dropped. Default: hartree\nonsite: charge-charge onsite potential. Overrides both Hartree and Fock potentials for onsite interactions. Default: hartree(0)\ncharge: a number (in single-orbital systems) or a matrix (in multi-orbital systems) representing the charge operator on each site. Default: I\nnambu::Bool: specifies whether the model is defined in Nambu space. In such case, charge should also be in Nambu space, typically SA[1 0; 0 -1] or similar. Default: false\nnamburotation::Bool: if nambu == true and spinful systems, specifies whether the spinor basis is [c↑, c↓, c↓⁺, -c↑⁺] (namburotation = true) or [c↑, c↓, c↑⁺, c↓⁺] (namburotation = false). Default: false\nselector::NamedTuple: a collection of hopselector directives that defines the pairs of sites (pair_selection above) that interact through the charge-charge potential. Default: (; range = 0) (i.e. onsite)\n\nAny additional keywords kw are passed to the densitymatrix function used to compute the mean field, see above\n\nEvaluation and Indexing\n\nM(µ = 0, kBT = 0; params...) # where M::MeanField\n\nBuild an Φ::CompressedOrbitalMatrix, which is a special form of OrbitalSliceMatrix that can be indexed at pairs of individual sites, e.g. ϕ[sites(2), sites(1)] to return an SMatrix. This type of matrix is less flexible than OrbitalSliceMatrix but is fully static, and can encode symmetries. Its features are implementation details and are bound to change. The returned Φ is just meant to be used in non-spatial models, see Examples below.\n\nExamples\n\njulia> model = hopping(I) - @onsite((i; phi = zerofield) --> phi[i]); # see zerofield docstring\n\njulia> g = LP.honeycomb() |> hamiltonian(model, orbitals = 2) |> supercell((1,-1)) |> greenfunction;\n\njulia> M = meanfield(g; selector = (; range = 1), charge = I, potential = 0.05)\nMeanField{SMatrix{2, 2, ComplexF64, 4}} : builder of Hartree-Fock-Bogoliubov mean fields\n Charge type : 2 × 2 blocks (ComplexF64)\n Hartree pairs : 14\n Mean field pairs : 28\n Nambu : false\n\njulia> phi0 = M(0.2, 0.3);\n\njulia> phi0[sites(1), sites(2)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.00109527+0.0im 0.0+0.0im\n 0.0+0.0im 0.00109527+0.0im\n\njulia> phi0[sites(1)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.296672+0.0im 0.0+0.0im\n 0.0+0.0im 0.296672+0.0im\n\njulia> phi1 = M(0.2, 0.3; phi = phi0);\n\njulia> phi1[sites(1), sites(2)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.00307712+0.0im 0.0+0.0im\n 0.0+0.0im 0.00307712+0.0im\n\nSee also\n\n`zerofield`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.neighbors","page":"API","title":"Quantica.neighbors","text":"neighbors(n::Int)\n\nCreate a Neighbors(n) object that represents a hopping range to distances corresponding to the n-th nearest neighbors in a given lattice, irrespective of their sublattice. Neighbors at equal distance do not count towards n.\n\nneighbors(n::Int, lat::Lattice)\n\nObtain the actual nth-nearest-neighbot distance between sites in lattice lat.\n\nSee also\n\n`hopping`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.onsite","page":"API","title":"Quantica.onsite","text":"onsite(o; sites...)\nonsite(r -> o(r); sites...)\n\nBuild a TighbindingModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce a Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nonsite(m::{TighbindingModel,ParametricModel}; sites...)\n\nConvert m into a new model with just onsite terms acting on sites.\n\nModel algebra\n\nModels can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.\n\nExamples\n\njulia> model = onsite(r -> norm(r) * SA[0 1; 1 0]; sublats = :A) - hopping(I; range = 2)\nTightbindingModel: model with 2 terms\n OnsiteTerm{Function}:\n Region : any\n Sublattices : A\n Cells : any\n Coefficient : 1\n HoppingTerm{LinearAlgebra.UniformScaling{Bool}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : 2.0\n Reverse hops : false\n Coefficient : -1\n\njulia> LP.cubic() |> supercell(4) |> hamiltonian(model, orbitals = 2)\nHamiltonian{Float64,3,3}: Hamiltonian on a 3D Lattice in 3D space\n Bloch harmonics : 27\n Harmonic size : 64 × 64\n Orbitals : [2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 64\n Hoppings : 2048\n Coordination : 32.0\n\nSee also\n\n`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.orbaxes","page":"API","title":"Quantica.orbaxes","text":"orbaxes(A::OrbitalSliceArray)\n\nReturn the orbital axes of A. This is a tuple of OrbitalSliceGrouped objects that can be used e.g. to index another OrbitalSliceArray or to inspect the indices of each site with siteindexdict.\n\nExamples\n\njulia> g = HP.graphene(orbitals = 2) |> supercell((1,-1)) |> greenfunction;\n\njulia> d = ldos(g[cells = SA[0]])(2); summary(d)\n\"8-element OrbitalSliceVector{Float64,Array}\"\n\njulia> a = only(orbaxes(d))\nOrbitalSliceGrouped{Float64,2,1} : collection of subcells of orbitals (grouped by sites) for a 1D lattice in 2D space\n Cells : 1\n Cell range : ([0], [0])\n Total sites : 4\n\njulia> siteindexdict(a)\n4-element Dictionaries.Dictionary{Quantica.CellIndices{1, Int64, Quantica.SiteLike}, UnitRange{Int64}}\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 1 │ 1:2\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 2 │ 3:4\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 3 │ 5:6\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 4 │ 7:8\n\nSee also\n\n`siteindexdict`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.path","page":"API","title":"Quantica.path","text":"Quantica.path(O::Josephson, args...)\nQuantica.path(O::DensityMatrix, args...)\n\nReturn the vertices of the polygonal integration path used to compute O(args...).\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.plusadjoint","page":"API","title":"Quantica.plusadjoint","text":"plusadjoint(t::Model)\n\nReturns a model t + t'. This is a convenience function analogous to the + h.c. notation.\n\nExample\n\njulia> model = hopping(im, sublats = :A => :B) |> plusadjoint\nTightbindingModel: model with 2 terms\n HoppingTerm{Complex{Bool}}:\n Region : any\n Sublattice pairs : :A => :B\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n HoppingTerm{Complex{Int64}}:\n Region : any\n Sublattice pairs : :A => :B\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : true\n Coefficient : 1\n\njulia> h = hamiltonian(LP.honeycomb(), model)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> h((0,0))\n2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 0.0-3.0im\n 0.0+3.0im ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serialize","page":"API","title":"Quantica.serialize","text":"serialize(as::AppliedSerializer{T}; params...)\n\nConstruct a Vector{T} that encodes a selection of matrix elements of h(; params...) where h = Quantica.parent_hamiltonian(as) is the AbstractHamiltonian used to build the AppliedSerializer, see serializer.\n\nserialize(m::OrbitalSliceArray)\n\nReturn an Array of the same eltype as m that contains all the stored matrix elements of m. See deserialize for the inverse operation.\n\nserialize(T::Type, m::OrbitalSliceArray)\n\nReinterpret serialize(m) as a collection with eltype T\n\nSee also\n\n`serializer`, `serialize!`, `deserialize`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serialize!","page":"API","title":"Quantica.serialize!","text":"serialize!(v, as::AppliedSerializer; params...)\n\nFill v in-place with the output of serialize(as; params...), see serialize for details.\n\nSee also\n\n`serialize`, `serialize!`, `deserialize`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serializer","page":"API","title":"Quantica.serializer","text":"serializer(T::Type, selectors...; parameter = :stream, encoder = identity, decoder = identity)\n\nConstruct a abstract s::Serializer object defines the rules to serialize and deserialize an AbstractHamiltonian, i.e. to translate the matrix elements selected by selectors (SiteSelectors or HopSelectors) into a 1D array of scalars of type T.\n\nserializer(T::Type; kw...)\n\nEquivalent to serializer(T, siteselector(), hopselector(); kw...), i.e. with all onsites and hoppings included in selection.\n\nserializer(T::Type, h::AbstractHamiltonian, selectors...; kw...)\n\nApplies a Serializer object like those above, and applies it to h::AbstractHamiltonian to produce an AppliedSerializer{T,<:AbstractHamiltonian}, that can be used to serialize and deserialize h. See serialize and deserialize for further details.\n\nserializer(h::AbstractHamiltonian{T}, selectors...; kw...)\n\nEquivalent to serializer(Complex{T}, h, selectors...; kw...).\n\nKeywords\n\nparameter: the parameter name used to address the serialized vector after transforming an AppliedSerializer into a ParametricHamiltonian, see below. Default: :stream.\nencoder: a function s -> vec that translates a single matrix element s into an collection vec of scalars of type T. Also supported is encoder = (s->vec, (s,s´)->vec´), which applies the second function to hoppings hᵢⱼ = s and their adjoint hⱼᵢ = s´ to encode both in a single collection vec´ (onsites hᵢᵢ are still encoded using the first single-argument function). This is useful for Hermitian Hamiltonians, where hⱼᵢ can be derived from hᵢⱼ. Default: identity.\ndecoder: the inverse function vec -> s of the encoder. If encoder is a tuple, decoder should also be a tuple of the inverse functions of each encoder function. Default: identity.\n\nNote: for an h::AbstractHamiltonian with a non-uniform number of orbitals, the matrix element passed to the encoder should always be assumed to be a square SMatrix of a fixed size that can fit all sites, padded with zeros if necessary (see \"Element type\" when displaying it, and the output of h[unflat(dn)]). Likewise, the decoder should return a square SMatrix of the same size, or any other container that can be converted to one. The latter is also important in cases with a uniform orbital number greater than one (non-scalar element type).\n\nThe user can check that the encoder and decoder are mutual inverses with Quantica.check(s; params...) where params is any choice of Hamiltonian parameters. This essentially checks that h(; params) == deserialize(s, serialize(s; params...); params...) holds.\n\nCall syntax and ParametricHamiltonians\n\nas(; params...)\n\nTransforms as::AppliedSerializer{T,<:ParametricHamiltonian} into an as´::AppliedSerializer{T,<:Hamiltonian} where the enclosed h is replaced by h´ = h(; params...). The in-place (aliasing) version of the above is Quantica.call!(as; params...). Note that the enclosed AbstractHamiltonians can be retrieved with e.g. Quantica.parent_hamiltonian(as).\n\nhamiltonian(as::AppliedSerializer)\n\nBuilds a ph::ParametricHamiltonian by adding as as a parametric modifier (similar to @onsite! or @hopping!) to the h::AbstractHamiltonian enclosed in as. As a result, ph acquires a new parameter of the name given by the parameter keyword specified originally (:stream by default, see above). This parameter takes a serialized stream (e.g. the output of serialize(as)) and replaces the corresponding elements in ph.\n\nh |> s\n\nFor s::Serializer and h::AbstractHamiltonian, converts s into an as::AppliedSerializer by applying it to h and then adds as as a parametric modifier to h to produce a ph::ParametricHamiltonian, as above. Note that h |> as with as::AppliedSerializer is not allowed, since as can only be a modifier of its enclosed AbstractHamiltonian.\n\nExamples\n\njulia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);\n\njulia> as = serializer(Float64, h1; encoder = s -> reim(s), decoder = v -> complex(v[1], v[2]))\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : ParametricHamiltonian\n Object parameters : [:U]\n Stream parameter : :stream\n Output eltype : Float64\n Encoder/Decoder : Single\n Length : 6\n\njulia> v = serialize(as; U = 4)\n6-element Vector{Float64}:\n -4.0\n 0.0\n -0.0\n -1.0\n 0.0\n 1.0\n\njulia> h2 = deserialize!(as, v);\n\njulia> h2 == h1(U = 4)\ntrue\n\njulia> h3 = hamiltonian(as)\nParametricHamiltonian{Float64,1,1}: Parametric Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 1 × 1\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 1\n Hoppings : 2\n Coordination : 2.0\n Parameters : [:U, :stream]\n\njulia> h3(stream = v, U = 5) == h1(U = 4) # stream overwrites the U=5 onsite terms\ntrue\n\nSee also\n\n`serialize`, `serialize!`, `deserialize`, `deserialize!`, `siteselector`, `hopselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.siteindexdict","page":"API","title":"Quantica.siteindexdict","text":"siteindexdict(axis::OrbitalSliceGrouped)\n\nReturn a dictionary of CellSites representing single sites in an orbital axis of an OrbitalSliceArray, typically obtained with orbaxes. See orbaxes for an example.\n\nSee also\n\n`orbaxes`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sitepairs","page":"API","title":"Quantica.sitepairs","text":"sitepairs(s::HopSelector; kernel = missing)\n\nCreate a selection of site pairs s::SparseIndices used to sparsely index into a g::GreenFunction or g::GreenSolution, as g[s]. Of the resulting OrbitalSliceMatrix only the selected pairs of matrix elements will be computed, leaving the rest as zero (sparse matrix). The sparse matrix spans the minimum number of complete unit cells to include all site pairs\n\nIf kernel = Q (a matrix instead of missing), each of these site blocks gᵢⱼ will be replaced by Tr(kernel * gᵢⱼ).\n\nsitepairs(; kernel = missing, hops...)\n\nEquivalent to sitepairs(hopselector(; hops...); kernel)\n\nKeywords\n\n- `kernel`: if missing, all orbitals blocks `gᵢⱼ = g[i, j]` between selected sites pairs (i,j) are returned when indexing `g[sitepairs(...)]`. Otherwise, `gᵢⱼ` is replaced by `Tr(gᵢⱼ*kernel)`.\n\nExample\n\njulia> g = HP.graphene(orbitals = 2, a0 = 1) |> attach(nothing, cells = (0,0)) |> greenfunction();\n\njulia> summary(g(1)[sitepairs(range = 1)]) # g(ω=1) site blocks between all sites in zero cell and all other sites at distance 1\n\"28×4 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}\"\n\njulia> summary(g(1)[sitepairs(range = 1, kernel = SA[1 0; 0 -1])]) # σz spin density of the above\n\"14×2 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}\"\n\nSee also\n\n`diagonal`, `hopselector`, `greenfunction`, `ldos`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sites","page":"API","title":"Quantica.sites","text":"sites(lat::Lattice[, sublat])\n\nReturn a collection of site positions in the unit cell of lattice lat. If a sublat::Symbol or sublat::Int is specified, only sites for the specified sublattice are returned.\n\nsites(ls::LatticeSlice)\n\nReturn a collection of positions of a LatticeSlice, generally obtained by indexing a lattice lat[sel...] with some siteselector keywords sel. See also lattice.\n\nNote: the returned collections can be of different types (vectors, generators, views...)\n\nsites(cell_index, site_indices)\nsites(site_indices)\n\nConstruct a simple selector of sites, of type CellSites, with given site_indices in a given cell at cell_index. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_index should be a collection of L integers, where L is the lattice dimension. If omitted, cell_index defaults to the zero-th cell (0,...).\n\nCellSites produced with sites can be used to index Lattices, AbstractHamiltonians, GreenFunctions, GreenSlices, OrbitalSliceArrays, etc. Note that selecting sites based on cell and site indices requires finding the indices beforehand, which can be done e.g. through plotting the system with qplot. This is lower level and potentially more fragile than using siteselectors, as indices are chosen freely by Quantica in an unspecified way, but it does have a smaller overhead.\n\nExamples\n\njulia> sites(LatticePresets.honeycomb(), :A)\n1-element view(::Vector{SVector{2, Float64}}, 1:1) with eltype SVector{2, Float64}:\n [0.0, -0.2886751345948129]\n\nSee also\n\n`lattice`, `siteselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.siteselector","page":"API","title":"Quantica.siteselector","text":"siteselector(; region = missing, sublats = missing, cells = missing)\n\nReturn a SiteSelector object that can be used to select a finite set of sites in a lattice. Sites at position r::SVector{E}, belonging to a cell of index n::SVector{L,Int} and to a sublattice with name s::Symbol will be selected only if\n\n`region(r) && s in sublats && n in cells`\n\nAny missing region, sublat or cells will not be used to constraint the selection.\n\nGeneralization\n\nWhile sublats and cells are usually collections of Symbols and SVectors, respectively, they also admit other possibilities:\n\nIf either cells or sublats are a single cell or sublattice, they will be treated as single-element collections\nIf sublat is a collection of Integers, it will refer to sublattice numbers.\nIf cells is an i::Integer, it will be converted to an SVector{1}\nIf cells is a collection, each element will be converted to an SVector.\nIf cells is a boolean function, n in cells will be the result of cells(n)\n\nUsage\n\nAlthough the constructor siteselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering sites, which themselves call siteselector internally as needed. Some of these functions are\n\ngetindex(lat::Lattice; kw...) : return a LatticeSlice with sites specified by kw (also lat[kw...])\nsupercell(lat::Lattice; kw...) : returns a bounded lattice with the sites specified by kw\nonsite(...; kw...) : onsite model term to be applied to sites specified by kw\n@onsite!(...; kw...) : onsite modifier to be applied to sites specified by kw\n\nSee also\n\n`hopselector`, `lattice`, `supercell`, `onsite`, `@onsite`, `@onsite!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.spectrum","page":"API","title":"Quantica.spectrum","text":"spectrum(h::AbstractHamiltonian, ϕs; solver = EigenSolvers.LinearAlgebra(), transform = missing, params...)\n\nCompute the Spectrum of the Bloch matrix h(ϕs; params...) using the specified eigensolver, with transform applied to the resulting eigenenergies, if not missing. Eigenpairs are sorted by the real part of their energy. See EigenSolvers for available solvers and their options.\n\nspectrum(h::AbstractHamiltonian; kw...)\n\nFor a 0D h, equivalent to spectrum(h, (); kw...)\n\nspectrum(m::AbstractMatrix; solver = EigenSolvers.LinearAlgebra()], transform = missing)\n\nCompute the Spectrum of matrix m using solver and transform.\n\nspectrum(b::Bandstructure, ϕs)\n\nCompute the Spectrum corresponding to slicing the bandstructure b at point ϕs of its base mesh (see bands for details).\n\nIndexing and destructuring\n\nEigenenergies ϵs::Tuple and eigenstates ψs::Matrix can be extracted from a spectrum sp using any of the following\n\nϵs, ψs = sp\nϵs = first(sp)\nϵs = energies(sp)\nψs = last(sp)\nψs = states(sp)\n\nIn addition, one can extract the n eigenpairs closest (in real energy) to a given energy ϵ₀ with\n\nϵs, ψs = sp[1:n, around = ϵ₀]\n\nMore generally, sp[inds, around = ϵ₀] will take the eigenpairs at position given by inds after sorting by increasing distance to ϵ₀, or the closest eigenpair in inds is missing. If around is omitted, the ordering in sp is used.\n\nExamples\n\njulia> h = HP.graphene(t0 = 1); spectrum(h, (0,0))\nSpectrum{Float64,ComplexF64} :\nEnergies:\n2-element Vector{ComplexF64}:\n -2.9999999999999982 + 0.0im\n 2.9999999999999982 + 0.0im\nStates:\n2×2 Matrix{ComplexF64}:\n -0.707107+0.0im 0.707107+0.0im\n 0.707107+0.0im 0.707107+0.0im\n\nSee also\n\n`EigenSolvers`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.states","page":"API","title":"Quantica.states","text":"states(sp::Spectrum)\n\nReturns the eigenstates in sp as columns of a matrix. Equivalent to last(sp).\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.subdiv","page":"API","title":"Quantica.subdiv","text":"subdiv((x₁, x₂, ..., xₙ), (p₁, p₂, ..., pₙ₋₁))\n\nBuild a vector of values between x₁ and xₙ containing all xᵢ such that in each interval [xᵢ, xᵢ₊₁] there are pᵢ equally space values.\n\nsubdiv((x₁, x₂, ..., xₙ), p)\n\nSame as above with all pᵢ = p\n\nsubdiv(x₁, x₂, p)\n\nEquivalent to subdiv((x₁, x₂), p) == collect(range(x₁, x₂, length = p))\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sublat","page":"API","title":"Quantica.sublat","text":"sublat(sites...; name::Symbol = :A)\nsublat(sites::AbstractVector; name::Symbol = :A)\n\nCreate a Sublat{E,T} that adds a sublattice, of name name, with sites at positions sites in E dimensional space. Sites positions can be entered as Tuples or SVectors.\n\nExamples\n\njulia> sublat((0.0, 0), (1, 1), (1, -1), name = :A)\nSublat{2,Float64} : sublattice of Float64-typed sites in 2D space\n Sites : 3\n Name : :A\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.supercell","page":"API","title":"Quantica.supercell","text":"supercell(lat::Lattice{E,L}, v::NTuple{L,Integer}...; seed = missing, kw...)\nsupercell(lat::Lattice{E,L}, uc::SMatrix{L,L´,Int}; seed = missing, kw...)\n\nGenerate a new Lattice from an L-dimensional lattice lat with a larger unit cell, such that its Bravais vectors are br´= br * uc. Here uc::SMatrix{L,L´,Int} is the integer supercell matrix, with the L´ vectors vs as its columns. If no v are given, the new lattice will have no Bravais vectors (i.e. it will be bounded, with its shape determined by keywords kw...). Likewise, if L´ < L, the resulting lattice will be bounded along L´ - L directions, as dictated by kw....\n\nOnly sites selected by siteselector(; kw...) will be included in the supercell (see siteselector for details on the available keywords kw). If no keyword region is given in kw, a single Bravais unit cell perpendicular to the v axes will be selected along the L-L´ bounded directions.\n\nsupercell(lattice::Lattice{E,L}, factors::Integer...; seed = missing, kw...)\n\nCall supercell with different scaling along each Bravais vector, so that supercell matrix uc is Diagonal(factors). If a single factor is given, uc = SMatrix{L,L}(factor * I)\n\nsupercell(h::Hamiltonian, v...; mincoordination = 0, seed = missing, kw...)\n\nTransform the Lattice of h to have a larger unit cell, while expanding the Hamiltonian accordingly.\n\nKeywords\n\nseed::NTuple{L,Integer}: starting cell index to perform search of included sites. By default seed = missing, which makes search start from the zero-th cell.\nmincoordination::Integer: minimum number of nonzero hopping neighbors required for sites to be included in the supercell. Sites with less coordination will be removed recursively, until all remaining sites satisfy mincoordination.\n\nCurrying\n\nlat_or_h |> supercell(v...; kw...)\n\nCurried syntax, equivalent to supercell(lat_or_h, v...; kw...)\n\nExamples\n\njulia> LatticePresets.square() |> supercell((1, 1), region = r -> 0 < r[1] < 5)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 1.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (8,) --> 8 total per unit cell\n\njulia> LatticePresets.honeycomb() |> supercell(3)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 2.598076], [-1.5, 2.598076]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (9, 9) --> 18 total per unit cell\n\nSee also\n\n`supercell`, `siteselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.torus","page":"API","title":"Quantica.torus","text":"torus(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))\n\nFor an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new h´::AbstractHamiltonian on a bounded torus, i.e. with all Bravais vectors eliminated by stitching the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along stitched directions will pick up a Bloch phase exp(-iϕ⋅dn).\n\nIf a number L´ of phases ϕᵢ are : instead of numbers, the corresponding Bravais vectors will not be stitched, and the resulting h´ will have a finite lattice dimension L´.\n\nCurrying\n\nh |> torus((ϕ₁, ϕ₂,...))\n\nCurrying syntax equivalent to torus(h, (ϕ₁, ϕ₂,...)).\n\nExamples\n\njulia> h2D = HP.graphene(); h1D = torus(h2D, (:, 0.2))\nHamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 4\n Coordination : 2.0\n\njulia> h2D((0.3, 0.2)) ≈ h1D(0.3)\ntrue\n\nSee also\n\n`hamiltonian`, `supercell`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.transform","page":"API","title":"Quantica.transform","text":"transform(lat_or_h::Union{Lattice,AbstractHamiltonian}, f::Function)\n\nBuild a new lattice or hamiltonian transforming each site positions r into f(r).\n\nCurrying\n\nx |> transform(f::Function)\n\nCurried version of transform, equivalent to transform(f, x)\n\nNote: Unexported Quantica.transform! is also available for in-place transforms. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.\n\nExamples\n\njulia> LatticePresets.square() |> transform(r -> 3r)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[3.0, 0.0], [0.0, 3.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell\n\nSee also\n\n`translate`, `reverse`, `reverse!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.translate","page":"API","title":"Quantica.translate","text":"translate(lat::Lattice, δr)\n\nBuild a new lattice translating each site positions from r to r + δr, where δr can be a NTuple or an SVector in embedding space.\n\nCurrying\n\nx |> translate(δr)\n\nCurried version of translate, equivalent to translate(x, δr)\n\nNote: Unexported Quantica.translate! is also available for in-place translations. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.\n\nExamples\n\njulia> LatticePresets.square() |> translate((3,3)) |> sites\n1-element Vector{SVector{2, Float64}}:\n [3.0, 3.0]\n\n\nSee also\n\n`transform`, `reverse`, `reverse!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.transmission","page":"API","title":"Quantica.transmission","text":"transmission(gs::GreenSlice)\n\nGiven a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object T::Transmission representing the normal transmission probability Tᵢⱼ(ω) from contact j to i at energy ω. It can be written as Tᵢⱼ = TrgʳΓⁱgᵃΓʲ. Here gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i\n\nFull evaluation\n\nT(ω; params...)\n\nCompute the transmission Tᵢⱼ(ω) at a given ω and for the specified params of g.\n\nExamples\n\njulia> # A central system g0 with two 1D leads and transparent contacts\n\njulia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> T = transmission(g0[2, 1])\nTransmission: total transmission between two different contacts\n From contact : 1\n To contact : 2\n\njulia> T(0.2) ≈ 3 # The difference from 3 is due to the automatic `im*sqrt(eps(Float64))` added to `ω`\nfalse\n\njulia> T(0.2 + 1e-10im) ≈ 3\ntrue\n\nSee also\n\n`greenfunction`, `conductance`, `ldos`, `current`, `josephson`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.unflat","page":"API","title":"Quantica.unflat","text":"unflat(dn)\n\nConstruct an u::Unflat object wrapping some indices dn. This object is meant to be used to index into a h::AbstractHamiltonian as h[u], which returns an non-flattened version of the Bloch harmonic h[dn]. Each element in the matrix h[u] is an SMatrix block representing onsite or hoppings between whole sites, in contrast to h[dn] where they are scalars representing single orbitals. This is only relevant for multi-orbital Hamiltonians h.\n\nunflat()\n\nEquivalent to unflat(())\n\nExamples\n\njulia> h = HP.graphene(orbitals = 2); h[unflat(0,0)]\n2×2 SparseArrays.SparseMatrixCSC{SMatrix{2, 2, ComplexF64, 4}, Int64} with 2 stored entries:\n ⋅ [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]\n [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im] ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.@hopping","page":"API","title":"Quantica.@hopping","text":"@hopping((; params...) -> t(; params...); hops...)\n@hopping((r, dr; params...) -> t(r; params...); hops...)\n\nBuild a ParametricModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of site orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nThe difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.\n\n@hopping((ω; params...) -> Σᵢⱼ(ω; params...); hops...)\n@hopping((ω, r, dr; params...) -> Σᵢⱼ(ω, r, dr; params...); hops...)\n\nSpecial form of a parametric hopping amplitude meant to model a self-energy (see attach).\n\n@hopping((i, j; params...) --> ...; sites...)\n@hopping((ω, i, j; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nModel algebra\n\nParametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.\n\nExamples\n\njulia> model = @hopping((r, dr; t = 1, A = Returns(SA[0,0])) -> t * cis(-dr' * A(r)))\nParametricModel: model with 1 term\n ParametricHoppingTerm{ParametricFunction{2}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n Argument type : spatial\n Parameters : [:t, :A]\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 8 × 8\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 24\n Coordination : 3.0\n Parameters : [:A, :t]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@hopping!","page":"API","title":"Quantica.@hopping!","text":"@hopping!((t; params...) -> t´(t; params...); hops...)\n@hopping!((t, r, dr; params...) -> t´(t, r, dr; params...); hops...)\n\nBuild a uniform or position-dependent hopping term modifier, respectively, acting on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. The original hopping amplitude is t, and the modified hopping is t´, which is a function of t and possibly r, dr. It may optionally also depend on parameters, enconded in params.\n\nModifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.\n\n@hopping!((t, i, j; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nExamples\n\njulia> model = hopping(1); peierls = @hopping!((t, r, dr; A = r -> SA[0,0]) -> t * cis(-dr' * A(r)))\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : spatial\n Parameters : [:A]\n\njulia> LP.honeycomb() |> hamiltonian(model) |> supercell(10) |> hamiltonian(peierls)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 200 × 200\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 600\n Coordination : 3.0\n Parameters : [:A]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@onsite","page":"API","title":"Quantica.@onsite","text":"@onsite((; params...) -> o(; params...); sites...)\n@onsite((r; params...) -> o(r; params...); sites...)\n\nBuild a ParametricModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nThe difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.\n\n@onsite((ω; params...) -> Σᵢᵢ(ω; params...); sites...)\n@onsite((ω, r; params...) -> Σᵢᵢ(ω, r; params...); sites...)\n\nSpecial form of a parametric onsite potential meant to model a self-energy (see attach).\n\n@onsite((i; params...) --> ...; sites...)\n@onsite((ω, i; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nModel algebra\n\nParametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.\n\nExamples\n\njulia> model = @onsite((r; dμ = 0) -> (r[1] + dμ) * I; sublats = :A) + @onsite((; dμ = 0) -> - dμ * I; sublats = :B)\nParametricModel: model with 2 terms\n ParametricOnsiteTerm{ParametricFunction{1}}\n Region : any\n Sublattices : A\n Cells : any\n Coefficient : 1\n Argument type : spatial\n Parameters : [:dμ]\n ParametricOnsiteTerm{ParametricFunction{0}}\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1\n Argument type : spatial\n Parameters : [:dμ]\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model, orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 8 × 8\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 8\n Hoppings : 0\n Coordination : 0.0\n Parameters : [:dμ]\n\nSee also\n\n`onsite`, `hopping`, `@hopping`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@onsite!","page":"API","title":"Quantica.@onsite!","text":"@onsite!((o; params...) -> o´(o; params...); sites...)\n@onsite!((o, r; params...) -> o´(o, r; params...); sites...)\n\nBuild a uniform or position-dependent onsite term modifier, respectively, acting on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The original onsite potential is o, and the modified potential is o´, which is a function of o and possibly r. It may optionally also depend on parameters, enconded in params.\n\nModifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.\n\n@onsite((o, i; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nExamples\n\njulia> model = onsite(0); disorder = @onsite!((o; W = 0) -> o + W * rand())\nOnsiteModifier{ParametricFunction{1}}:\n Region : any\n Sublattices : any\n Cells : any\n Argument type : spatial\n Parameters : [:W]\n\njulia> LP.honeycomb() |> hamiltonian(model) |> supercell(10) |> hamiltonian(disorder)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 200 × 200\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 200\n Hoppings : 0\n Coordination : 0.0\n Parameters : [:W]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@hopping`, `@hopping!`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"tutorial/observables/#Observables","page":"Observables","title":"Observables","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We are almost at our destination now. We have defined a Lattice, a Model for our system, we applied the Model to the Lattice to obtain a Hamiltonian or a ParametricHamiltonian, and finally, after possibly attaching some contacts to outside reservoirs and specifying a GreenSolver, we obtained a GreenFunction. It is now time to use the GreenFunction to obtain some observables of interest.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Currently, we have the following observables built into Quantica.jl (with more to come in the future)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"ldos: computes the local density of states at specific energy and sites\ndensitymatrix: computes the density matrix at thermal equilibrium on specific sites.\ncurrent: computes the local current density along specific directions, and at specific energy and sites\ntransmission: computes the total transmission between contacts\nconductance: computes the differential conductance dIᵢ/dVⱼ between contacts i and j\njosephson: computes the supercurrent and the current-phase relation through a given contact in a superconducting system","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"See the corresponding docstrings for full usage instructions. Here we will present some basic examples","category":"page"},{"location":"tutorial/observables/#Local-density-of-states-(LDOS)","page":"Observables","title":"Local density of states (LDOS)","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Let us compute the LDOS in a cavity like in the previous section. Instead of computing the Green function between a contact to an arbitrary point, we can construct an object d = ldos(g(ω)) without any contacts. By using a small imaginary part in ω, we broaden the discrete spectrum, and obtain a finite LDOS. Then, we can pass d directly as a site shader to qplot","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> h = LP.square() |> onsite(4) - hopping(1) |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1]))));\n\njulia> g = h |> greenfunction;\n\njulia> d = ldos(g(0.1 + 0.001im))\nLocalSpectralDensitySolution{Float64} : local density of states at fixed energy and arbitrary location\n kernel : LinearAlgebra.UniformScaling{Bool}(true)\n\njulia> qplot(h, hide = :hops, sitecolor = d, siteradius = d, minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"LDOS\"","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that d[sites...] produces a vector with the LDOS at sites defined by siteselector(; sites...) (d[] is the ldos over all sites). We can also define a kernel to be traced over orbitals to obtain the spectral density of site-local observables (see diagonal slicing in the preceding section).","category":"page"},{"location":"tutorial/observables/#Density-matrix","page":"Observables","title":"Density matrix","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We can also compute the convolution of the density of states with the Fermi distribution f(ω)=1/(exp((ω-μ)/kBT) + 1), which yields the density matrix in thermal equilibrium, at a given temperature kBT and chemical potential μ. This is computed with ρ = densitymatrix(gs, (ωmin, ωmax)). Here gs = g[sites...] is a GreenSlice, and (ωmin, ωmax) are integration bounds (they should span the full bandwidth of the system). Then, ρ(µ, kBT = 0; params...) will yield a matrix over the selected sites for a set of model params.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> ρ = densitymatrix(g[region = RP.circle(1)], (-0.1, 8.1))\nDensityMatrix: density matrix on specified sites using solver of type DensityMatrixIntegratorSolver\n\njulia> @time ρ(4)\n 6.150548 seconds (57.84 k allocations: 5.670 GiB, 1.12% gc time)\n5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.5+0.0im -7.34893e-10-3.94035e-15im 0.204478+1.9366e-14im -7.34889e-10-1.44892e-15im -5.70089e-10+5.48867e-15im\n -7.34893e-10+3.94035e-15im 0.5+0.0im 0.200693-2.6646e-14im -5.70089e-10-1.95251e-15im -7.34891e-10-2.13804e-15im\n 0.204478-1.9366e-14im 0.200693+2.6646e-14im 0.5+0.0im 0.200693+3.55692e-14im 0.204779-4.27255e-14im\n -7.34889e-10+1.44892e-15im -5.70089e-10+1.95251e-15im 0.200693-3.55692e-14im 0.5+0.0im -7.34885e-10-3.49861e-15im\n -5.70089e-10-5.48867e-15im -7.34891e-10+2.13804e-15im 0.204779+4.27255e-14im -7.34885e-10+3.49861e-15im 0.5+0.0im","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that the diagonal is 0.5, indicating half-filling.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The default algorithm used here is slow, as it relies on numerical integration in the complex plane. Some GreenSolvers have more efficient implementations. If they exist, they can be accessed by omitting the (ωmin, ωmax) argument. For example, using GS.Spectrum:","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> @time g = h |> greenfunction(GS.Spectrum());\n 37.638522 seconds (105 allocations: 2.744 GiB, 0.79% gc time)\n\njulia> ρ = densitymatrix(g[region = RP.circle(1)])\nDensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver\n\njulia> @time ρ(4)\n 0.001659 seconds (9 allocations: 430.906 KiB)\n5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.5+0.0im -2.21437e-15+0.0im 0.204478+0.0im 2.67668e-15+0.0im 3.49438e-16+0.0im\n -2.21437e-15+0.0im 0.5+0.0im 0.200693+0.0im -1.40057e-15+0.0im -2.92995e-15+0.0im\n 0.204478+0.0im 0.200693+0.0im 0.5+0.0im 0.200693+0.0im 0.204779+0.0im\n 2.67668e-15+0.0im -1.40057e-15+0.0im 0.200693+0.0im 0.5+0.0im 1.81626e-15+0.0im\n 3.49438e-16+0.0im -2.92995e-15+0.0im 0.204779+0.0im 1.81626e-15+0.0im 0.5+0.0im","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note, however, that the computation of g is much slower in this case, due to the need of a full diagonalization. A better algorithm choice in this case is GS.KPM. It requires, however, that we define the region for the density matrix beforehand, as a nothing contact.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> @time g = h |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 10000, bandrange = (0,8)));\nComputing moments: 100%|█████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01\n 2.065083 seconds (31.29 k allocations: 11.763 MiB)\n\njulia> ρ = densitymatrix(g[1])\nDensityMatrix: density matrix on specified sites with solver of type DensityMatrixKPMSolver\n\njulia> @time ρ(4)\n 0.006580 seconds (3 allocations: 1.156 KiB)\n5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.5+0.0im 2.15097e-17+0.0im 0.20456+0.0im 2.15097e-17+0.0im 3.9251e-17+0.0im\n 2.15097e-17+0.0im 0.5+0.0im 0.200631+0.0im 1.05873e-16+0.0im 1.70531e-18+0.0im\n 0.20456+0.0im 0.200631+0.0im 0.5+0.0im 0.200631+0.0im 0.20482+0.0im\n 2.15097e-17+0.0im 1.05873e-16+0.0im 0.200631+0.0im 0.5+0.0im 1.70531e-18+0.0im\n 3.9251e-17+0.0im 1.70531e-18+0.0im 0.20482+0.0im 1.70531e-18+0.0im 0.5+0.0im","category":"page"},{"location":"tutorial/observables/#Current","page":"Observables","title":"Current","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"A similar computation can be done to obtain the current density, using J = current(g(ω), direction = missing). This time J[sᵢ, sⱼ] yields a sparse matrix of current densities along a given direction for each hopping (or the current norm if direction = missing). Passing J as a hopping shader yields the equilibrium current in a system. In the above example we can add a magnetic flux to make this current finite","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> h = LP.square() |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1])))) |> onsite(4) - @hopping((r, dr; B = 0.1) -> cis(B * dr[1] * r[2]));\n\njulia> g = h |> greenfunction;\n\njulia> J = current(g(0.1; B = 0.01))\nCurrentDensitySolution{Float64} : current density at a fixed energy and arbitrary location\n charge : LinearAlgebra.UniformScaling{Int64}(-1)\n direction : missing\n\njulia> qplot(h, siteradius = 0.08, sitecolor = :black, siteoutline = 0, hopradius = J, hopcolor = J, minmaxhopradius = (0, 2), hopcolormap = :balance, hopdarken = 0)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Current","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"note: Remember to construct supercell before applying position-dependent fields\nNote that we built the supercell before applying the model with the magnetic flux. Not doing so would make the gauge field be repeated in each unit cell when expanding the supercell. This was mentioned in the section on Hamiltonians, and is a common mistake when modeling systems with position dependent fields.","category":"page"},{"location":"tutorial/observables/#Transmission","page":"Observables","title":"Transmission","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The transmission Tᵢⱼ from contact j to contact i can be computed using transmission. This function accepts a GreenSlice between the contact. Let us recover the four-terminal setup of the preceding section, but let's make it bigger this time","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> hcentral = LP.square() |> hopping(-1) |> supercell(region = RP.circle(100) | RP.rectangle((202, 50)) | RP.rectangle((50, 202)))\n\njulia> glead = LP.square() |> hopping(-1) |> supercell((1, 0), region = r -> abs(r[2]) <= 50/2) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> Rot = r -> SA[0 -1; 1 0] * r; # 90º rotation function\n\njulia> g = hcentral |>\n attach(glead, region = r -> r[1] == 101) |>\n attach(glead, region = r -> r[1] == -101, reverse = true) |>\n attach(glead, region = r -> r[2] == 101, transform = Rot) |>\n attach(glead, region = r -> r[2] == -101, reverse = true, transform = Rot) |>\n greenfunction;\n\njulia> gx1 = abs2.(g(-3.96)[siteselector(), 1]);\n\njulia> qplot(hcentral, hide = :hops, siteoutline = 1, sitecolor = gx1, siteradius = gx1, minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Green","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"tip: Matrix and vector shaders\nIn the above example gx1 is a matrix with one row per orbital in hcentral. The color and radii of each site is obtained from the sum of each row. If gx1 were a vector, the color/radius of site i would be taken as gx1[i]. See plotlattice for more details and other shader types.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"It's apparent from the plot that the transmission from right to left (T₂₁ here) at this energy of 0.04 is larger than from right to top (T₃₁). Is this true in general? Let us compute the two transmissions as a function of energy. To show the progress of the calculation we can use a monitor package, such as ProgressMeter","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> using ProgressMeter\n\njulia> T₂₁ = transmission(g[2,1]); T₃₁ = transmission(g[3,1]); ωs = subdiv(-4, 4, 201);\n\njulia> T₂₁ω = @showprogress [T₂₁(ω) for ω in ωs]; T₃₁ω = @showprogress [T₃₁(ω) for ω in ωs];\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:02\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:00\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"ω/t\", ylabel = \"T(ω)\"); lines!(a, ωs, T₂₁ω, label = L\"T_{2,1}\"); lines!(a, ωs, T₃₁ω, label = L\"T_{3,1}\"); axislegend(\"Transmission\", position = :lt); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Total","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"So we indeed find that the 90-degree transmission T₃₁ is indeed larger than the forward transmission T₂₁ for all energies. The rapid oscillations are due to mesoscopic fluctuations.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"note: Total transmission vs transmission probability\nNote that transmission gives the total transmission, which is the sum of the transmission probability from each orbital in the source contact to any other orbital in the drain contact. As such it is not normalized to 1, but to the number of source orbitals. It also gives the local conductance from a given contact in units of e^2h according to the Landauer formula, G_j = e^2h sum_i T_ij(eV).","category":"page"},{"location":"tutorial/observables/#Conductance","page":"Observables","title":"Conductance","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Local and non-local differential conductance G_ij = dI_idV_j can be computed with G = conductance(g[i,j]). Calling G(ω) returns the conductance at bias eV = omega in units of e^2h. Let's look at the local differential conductance into the right contact in the previous example","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> G₁₁ = conductance(g[1,1])\nConductance{Float64}: Zero-temperature conductance dIᵢ/dVⱼ from contacts i,j, in units of e^2/h\n Current contact : 1\n Bias contact : 1\n\njulia> ωs = subdiv(-4, 4, 201); Gω = @showprogress [G₁₁(ω) for ω in ωs];\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:01\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"eV/t\", ylabel = \"G [e²/h]\"); lines!(a, ωs, Gω); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Local","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"warning: Sign of non-local conductance\nIf you compute a non-local conductance such as conductance(g[2,1])(ω) in this example you will note it is negative. This is actually expected. It means that the current flowing into the system through the right contact when you increase the bias in a different contact is negative, because the current is actually flowing out into the right reservoir.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The conductance can also be computed for hybrid (normal-superconducting) systems. To do so, one first needs to write the model in the Nambu representation, i.e. with particle and hole orbitals on each site (first particles, then holes). In the above examples amounts to switching hopping(-1) to hamiltonian(onsite(Δ*σx) - hopping(σz), orbitals = 2), with σx = SA[0 1; 1 0], σz = SA[1 0; 0 -1] and Δ the pairing amplitude. Then we must specify G₁₁ = conductance(g[1,1], nambu = true) to take into account Andreev reflections. The above example with left, bottom and top leads superconducting (with Δ=0.3) yields the following conductance G₁₁ in the right (normal) lead (we leave the implementation as an exercise for the reader).","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Local","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that within the gap Andreev reflection leads to an enhancement of conductance, since the contacts are transparent","category":"page"},{"location":"tutorial/observables/#Josephson","page":"Observables","title":"Josephson","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The above example showcases normal-superconductor (NS) conductance, which is a Fermi-surface process in response to an electric bias on the normal contacts. In contrast, supercorconductor-superconductor junctions, also known as Josephson junctions, can exhibit supercurrents carried by the full Fermi sea even without a bias. Usually, this supercurrent flows in response to a phase bias between the superconductors, where by phase we mean the complex phase of the Δ order parameter.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We can compute the supercurrent or the full current-phase relation of a Josephson junction with the command josephson(gs::GreenSlice, ωmax), where gs = g[contact_id] and ωmax is the full bandwidth of the system (i.e. the maximum energy, in absolute value, spanned by the Fermi sea). This latter quantity can be an estimate or even an upper bound, as it is just used to know up to which energy we should integrate the supercurrent. Let us see an example.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> σz = SA[1 0; 0 -1];\n\njulia> central_region = RP.circle(50) & !RP.circle(40) | RP.rectangle((4, 10), (-50, 0)) | RP.rectangle((4, 10), (50, 0));\n\njulia> h = LP.square() |> hamiltonian(hopping(-σz), orbitals = 2) |> supercell(region = central_region)\n\njulia> Σ(ω, Δ) = SA[-ω Δ; conj(Δ) -ω]/sqrt(1-abs2(Δ))\n\njulia> g = h |>\n attach(@onsite((ω; Δ = 0.2) -> Σ(ω, Δ)); region = r -> r[1] < -51) |>\n attach(@onsite((ω; Δ = 0.2, phase = 0) -> Σ(ω, Δ*cis(phase))); region = r -> r[1] > 51) |>\n greenfunction\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 2\n Contact solvers : (SelfEnergyModelSolver, SelfEnergyModelSolver)\n Contact sizes : (11, 11)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 2884 × 2884\n Orbitals : [2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 10800\n Coordination : 3.7448\n\njulia> J = josephson(g[1], 4.1)\nIntegrator: Complex-plane integrator\n Integration path : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)\n Integration options : (atol = 1.0e-7,)\n Integrand: :\n JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy\n kBT : 0.0\n Contact : 1\n Number of phase shifts : 0\n\njulia> qplot(g, children = (; sitecolor = :blue))","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Josephson","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"In this case we have chosen to introduce the superconducting leads with a model self-energy, corresponding to a BCS bulk, but any other self-energy form could be used. We have introduced the phase difference (phase) as a model parameter. We can now evaluate the zero-temperature Josephson current simply with","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> J(phase = 0)\n-1.974396994480587e-16\n\njulia> J(phase = 0.2)\n0.004617597139699372","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that finite temperatures can be taken using the kBT keyword argument for josephson, see docstring for details.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"One is often interested in the critical current, which is the maximum of the Josephson current over all phase differences. Quantica.jl can compute the integral over a collection of phase differences simultaneously, which is more efficient that computing them one by one. This is done with","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> φs = subdiv(0, pi, 11); J = josephson(g[1], 4.1; phases = φs)\n Integration path : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)\n Integration options : (atol = 1.0e-7,)\n Integrand: :\n JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy\n kBT : 0.0\n Contact : 1\n Number of phase shifts : 11\n\njulia> Iφ = J()\n11-element Vector{Float64}:\n 1.868862401627357e-14\n 0.007231421775452674\n 0.014242855188877\n 0.02081870760779799\n 0.026752065104401878\n 0.031847203848574666\n 0.0359131410974842\n 0.03871895510547465\n 0.039762442694035505\n 0.03680096751905469\n 2.7677727119798235e-14\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"φ\", ylabel = \"I [e/h]\"); lines!(a, φs, Iφ); scatter!(a, φs, Iφ); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Josephson","category":"page"},{"location":"examples/#Examples","page":"Examples","title":"Examples","text":"","category":"section"},{"location":"tutorial/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We now will show how to build a generic single-particle tight-binding model, with generic Hamiltonian","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"H = sum_ialpha jbeta c_ialpha^dagger V_alphabeta(r_i r_j)c_jalpha","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Here, α,β are orbital indices in each site, i,j are site indices, and rᵢ, rⱼ are site positions. In Quantica.jl we would write the above model as","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = onsite(r -> V(r, r)) + hopping((r, dr) -> V(r-dr/2, r+dr/2))\nTightbindingModel: model with 2 terms\n OnsiteTerm{Function}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n HoppingTerm{Function}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where V(rᵢ, rⱼ) is a function that returns a matrix (ideally an SMatrix) V_alphabeta(r_i r_j) of the required orbital dimensionality.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Note that when writing models we distinguish between onsite (rᵢ=rⱼ) and hopping (rᵢ≠rⱼ) terms. For the former, r is the site position. For the latter we use a bond-center and bond-distance (r, dr) parametrization of V, so that r₁, r₂ = r ∓ dr/2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"If the onsite and hopping amplitudes do not depend on position, we can simply use constants","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = onsite(1) - 2*hopping(1)\nTightbindingModel: model with 2 terms\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n HoppingTerm{Int64}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : -2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: Model term algebra\nNote that we can combine model terms as in the above example by summing and subtracting them, and using constant coefficients.","category":"page"},{"location":"tutorial/models/#HopSelectors","page":"Models","title":"HopSelectors","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"By default onsite terms apply to any site in a Lattice, and hopping terms apply to any pair of sites within nearest-neighbor distance (see the Hopping range: Neighbors(1) above).","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We can change this default by specifying a SiteSelector or HopSelector for each term. SiteSelectors where already introduced to create LatticeSlices. HopSelectors are very similar, but support slightly different keywords:","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"region: to restrict according to bond center r and bond vector dr\nsublats: to restrict source and target sublattices\ndcells: to restrict the distance in cell index\nrange: to restrict the distance in real space","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"As an example, a HopSelector that selects any two sites at a distance between 1.0 and the second-nearest neighbor distance, with the first belonging to sublattice :B and the second to sublattice :A, and their bond center inside a unit circle","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> hs = hopselector(range = (1.0, neighbors(2)), sublats = :B => :A, region = (r, dr) -> norm(r) < 1)\nHopSelector: a rule that defines a finite collection of hops between sites in a lattice\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : false","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We can now use this HopSelector to restrict the hoppings in a model, just as SiteSelectors can be used to restrict onsite terms","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = plusadjoint(hopping(1, hs)) - 2*onsite(1, sublats = :B)\nTightbindingModel: model with 3 terms\n HoppingTerm{Int64}:\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : false\n Coefficient : 1\n HoppingTerm{Int64}:\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : true\n Coefficient : 1\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Note that we can pass the Selector itself as a second argument to hopping and onsite, or alternatively use selector keywords directly as in the onsite above.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: plusadjoint function\nThe convenience function plusadjoint(term) = term + term' adds the Hermitian conjugate of its argument (term'), equivalent to the + h.c. notation often used in the literature.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"note: Index-agnostic modeling\nThe Quantica.jl approach to defining tight-binding models does not rely explicitly on site indices (i,j above), since these are arbitrary, and may even be beyond the control of the user (for example after using supercell). Instead, we rely on physical properties of sites, such as position, distance or sublattice.","category":"page"},{"location":"tutorial/models/#Parametric-Models","page":"Models","title":"Parametric Models","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"The models introduced above are non-parametric, in the sense that they encode fixed, numerical Hamiltonian matrix elements. In many problems, it is commonplace to have models that depend on a number of free parameters that will need to be adjusted during a calculation. For example, one may need to compute the phase diagram of a system as a function of a spin-orbit coupling or an applied magnetic field. For these cases, we have ParametricModels.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Parametric models are defined with","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"@onsite((; params...) -> ...; sites...)\n@onsite((r; params...) -> ...; sites...)\n@hopping((; params...) -> ...; hops...)\n@hopping((r, dr; params...) -> ...; hops...)","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where the params keyword arguments define the free parameters, together with (optional) default values. Here is an example of a hopping model with a Peierls phase in the symmetric gauge, with the magnetic field Bz and the zero-field hopping t as free parameters","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model_perierls = @hopping((r, dr; Bz = 0, t = 1) -> t * cis(-im * Bz/2 * SA[-r[2], r[1], 0]' * dr))\nParametricModel: model with 1 term\n ParametricHoppingTerm{ParametricFunction{2}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n Argument type : spatial\n Parameters : [:Bz, :t]","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"One can linearly combine parametric and non-parametric models freely, omit parameter default values, and use any of the functional argument forms described for onsite and hopping (although not the constant argument form):","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model´ = 2 * (onsite(1) - 2 * @hopping((; t) -> t))\nParametricModel: model with 2 terms\n ParametricHoppingTerm{ParametricFunction{0}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : -4\n Argument type : spatial\n Parameters : [:t]\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: Non-spatial parametric models with -->\nThe -> in the above parametric models @onsite and @hopping, but also in the modifiers below, can be changed to -->. This indicates that the function arguments are no longer treated as site or link positions r and dr, but as objects i, j representing destination and source sites. This allows to address sites directly instead of through their spatial location. See the Mean Field section for further details.","category":"page"},{"location":"tutorial/models/#Modifiers","page":"Models","title":"Modifiers","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"There is a third model-related functionality known as OnsiteModifiers and HoppingModifiers. Given a model that defines a set of onsite and hopping amplitudes on a subset of sites and hops, one can define a parameter-dependent modification of a subset of said amplitudes. This is a useful way to introduce a new parameter dependence on an already defined model. Modifiers are built with","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"@onsite!((o; params...) -> new_onsite; sites...)\n@onsite!((o, r; params...) -> new_onsite; sites...)\n@hopping((t; params...) -> new_hopping; hops...)\n@hopping((t, r, dr; params...) -> new_hopping; hops...)","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where the first argument o and t is the unmodified value of the onsite or hopping amplitude, respectively. Here sites and hops are once more keyword arguments to restrict the modification with a SiteSelector or HopSelector.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"For example, the following HoppingModifier inserts a Peierls phase on all the hopping in a given model","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model_perierls! = @hopping!((t, r, dr; B = 0) -> t * cis(-Bz/2 * SA[-r[2], r[1], 0]' * dr))\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : spatial\n Parameters : [:B]","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"The difference with model_perierls is that model_perierls! will never add any new hoppings. It will only modify previously existing hoppings in a model. Modifiers are not models themselves, and cannot be summed to other models. They are instead meant to be applied sequentially after applying a model.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"In the next section we show how models and modifiers can be used in practice to construct Hamiltonians.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"note: Mind the `;`\nWhile syntax like onsite(2, sublats = :B) and onsite(2; sublats = :B) are equivalent in Julia, due to the way keyword arguments are parsed, the same is not true for macro calls like @onsite, @onsite!, @hopping and @hopping!. These macros just emulate the function call syntax. But to work you must currently always use the ; separator for keywords. Hence, something like @onsite((; p) -> p; sublats = :B) works, but @onsite((; p) -> p, sublats = :B) does not.","category":"page"},{"location":"tutorial/bandstructures/#Bandstructures","page":"Bandstructures","title":"Bandstructures","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The eigenpairs (eigenvalues and eigenvectors) of a Hamiltonian or ParametricHamiltonian at given Bloch phases ϕᵢ can be obtained with spectrum:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.honeycomb() |> hopping(1); ϕᵢ = (0, π);\n\njulia> eᵢ, ψᵢ = spectrum(h, ϕᵢ; solver = EigenSolvers.LinearAlgebra())\nSpectrum{Float64,ComplexF64} :\nEnergies:\n2-element Vector{ComplexF64}:\n -1.0 + 0.0im\n 1.0 + 0.0im\nStates:\n2×2 Matrix{ComplexF64}:\n 0.707107-8.65956e-17im 0.707107-8.65956e-17im\n -0.707107+0.0im 0.707107+0.0im","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The above destructuring syntax assigns eigenvalues and eigenvectors to eᵢ and ψᵢ, respectively. The available eigensolvers and their options can be checked in the EigenSolvers docstrings. They are supported through the extension mechanism in Julia, so they require additional libraries to be loaded first, such as using Arpack or using ArnoldiMethod.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"warning: Arpack solver is not thread-safe\nEigenSolvers.Arpack relies on a Fortran library that is not currently thread-safe. If you launch Julia with multiple threads, they will not be used with this specific solver. Otherwise Arpack would segfault.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"We define a \"bandstructure\" of an h::AbstractHamiltonian as a linear interpolation of its eigenpairs over a portion of the Brillouin zone, which is discretized with a base mesh of ϕᵢ values. At each ϕᵢ of the base mesh, the Bloch matrix h(ϕᵢ) is diagonalized with spectrum. The adjacent eigenpairs eⱼ(ϕᵢ), ψⱼ(ϕᵢ) are then connected (\"stitched\") together into a number of band meshes with vertices (ϕᵢ..., eⱼ(ϕᵢ)) by maximizing the overlap of adjacent ψⱼ(ϕᵢ) (since the bands should be continuuous). Degenerate eigenpairs are collected into a single node of the band mesh.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The bandstructure of an h::AbstractHamiltonian is computed using bands:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> ϕ₁points = ϕ₂points = range(0, 2π, length = 19);\n\njulia> b = bands(h, ϕ₁points, ϕ₂points)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 720\n Edges : 2016\n Simplices : 1296","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The first argument is the AbstractHamiltonian. Here it is defined on an L=2 dimensional lattice. The subsequent arguments are collections of Bloch phases on each of the L axes of the Brillouin zone, whose direct product ϕ₁points ⊗ ϕ₂points defines our base mesh of ϕᵢ points. Here it is a uniform 19×19 grid. We can once more use qplot to visualize the bandstructure, or more precisely the band meshes:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> using GLMakie; qplot(b)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The dots on the bands are the band mesh vertices (ϕᵢ..., eⱼ(ϕᵢ)). They can be omitted with the qplot keyword hide = :nodes (or hide = :vertices, both are equivalent).","category":"page"},{"location":"tutorial/bandstructures/#Band-defects","page":"Bandstructures","title":"Band defects","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"Note that the uniform grid contains the Dirac points. This is the reason for the number 19 of Bloch phases used above. Note also that it is identified as a point in the bands with degeneracy = 2 (the rest have degeneracy = 1). As mentioned, the points on the bands are connected based on eigenstate overlaps between adjacent ϕᵢs. This interpolation algorithm can deal with subspace degeneracies, as here. However, Dirac points (and Diabolical Points in general) must belong to the mesh for the method to work. If the number of points is reduced to 18 per axis, the Dirac points become unavoidable band dislocations, that appear as missing simplices in the bands:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: Advanced: band defects and patching\nIf a Dirac point or other type of band dislocation point happens to not belong to the sampling grid, it can be added with the bands keyword defects. Then, it can be reconnected with the rest of the band by increasing the patches::Integer keyword (see bands docstring for details). This \"band repair\" functionality is experimental, and should only be necessary in some cases with Diabolical Points.","category":"page"},{"location":"tutorial/bandstructures/#Coordinate-mapping-and-band-linecuts","page":"Bandstructures","title":"Coordinate mapping and band linecuts","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The direct product of the ϕᵢpoints above define a rectangular mesh over which we want to compute the bandstructure. By default, this mesh is taken as a discretization of Bloch phases, so h(ϕᵢ) is diagonalized at each point of the base mesh. We might want, however, a different relation between the mesh and the parameters passed to h, for example if we wish to use wavevectors k instead of Bloch phases ϕᵢ = k⋅Aᵢ for the mesh. This is achieved with the mapping keyword, which accepts a function mapping = (mesh_points...) -> bloch_phases,","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.honeycomb() |> hopping(2); k₁points = range(-2π, 2π, length = 51); k₂points = range(-2π, 2π, length = 51);\n\njulia> Kpoints = [SA[cos(θ) -sin(θ); sin(θ) cos(θ)] * SA[4π/3,0] for θ in range(0, 5*2π/6, length = 6)];\n\njulia> ϕ(k...) = SA[k...]' * bravais_matrix(h)\nϕ (generic function with 1 method)\n\njulia> b = bands(h, k₁points, k₂points; mapping = ϕ, defects = Kpoints, patches = 20);\n\njulia> using GLMakie; qplot(b, hide = (:nodes, :wireframe), color = :orange)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"To compute a bandstructure linecut along a polygonal line in the Brillouin zone, we could once more use the mapping functionality, mapping a set of points xᵢ::Real in the mesh to Bloch phases ϕᵢ that defines the nodes of the polygonal path, and interpolating linearly between them. To avoid having to construct this mapping ourselves, mapping accepts a second type of input for this specific usecase, mapping = xᵢ => ϕᵢ. Here, ϕᵢ can be a collection of Tuples, SVector{L}, or even Symbols denoting common names for high-symmetry points in the Brillouin zone, such as :Γ, :K, :K´, :M, :X, :Y, and :Z. The following gives a Γ-K-M-Γ linecut for the bands above, where the (Γ, K, M, Γ) points lie at x = (0, 2, 3, 4), respectively, with 10 subdivisions in each segment,","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> b = bands(h, subdiv((0, 2, 3, 4), 10); mapping = (0, 2, 3, 4) => (:Γ, :K, :M, :Γ));\n\njulia> qplot(b, axis = (; xticks = ([0, 2, 3, 4], [\"Γ\", \"K\", \"M\", \"Γ\"]), ylabel = \"ϵ\"))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: subdiv\nThe subdiv function is a convenience function provided by Quantica.jl that generalizes range (see the corresponding docstring for comprehensive details). It is useful to create collections of numbers as subdivisions of intervals, as in the example above. In its simplest form subdiv(min, max, npoints) is is equivalent to range(min, max, npoints).","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The mapping keyword understand a third syntax that can be used to map a mesh to the space of Bloch phases and parameters of a ParametricHamiltonian. To this end we use mapping = (mesh_points...) -> ftuple(bloch_phases...; params...). The ftuple function creates a FrankenTuple, which is a hybrid between a Tuple and a NamedTuple. For example, in the following 1D SSH chain we can compute the bandstructure as a function of Bloch phase ϕ and hopping t´, and plot it using more customization options","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.linear() |> supercell(2) |> @hopping((r, dr; t = 1, t´ = 2) -> iseven(r[1]-1/2) ? t : t´);\n\njulia> b = bands(h, subdiv(0, 2π, 11), subdiv(0, 10, 11), mapping = (ϕ, y) -> ftuple(ϕ; t´ = y/5), patches = 20)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 249\n Edges : 664\n Simplices : 416\n\njulia> qplot(b, nodedarken = 0.5, axis = (; aspect = (1,1,1), perspectiveness = 0.5, xlabel = \"ϕ\", ylabel = \"t´/t\", zlabel = \"ϵ\"), fancyaxis = false)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"SSH","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"Note that since we didn't specify a value for t, it assumed its default t=1. In this case we needed to patch the defect at (ϕ, t´) = (π, 1) (topological transition) using the patches keyword to avoid a band dislocation.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"If no parameters are specified or mapped, they take their default values. For example, this produces the 1D bandstructure of the SSH model for the default t = 1, t´ = 2 over the default 1D mesh (49 points, uniformly distributed in [-π, π])","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> qplot(bands(h))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"SSH","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: Experimental `Quantica.gaps` and `Quantica.decay_lengths` for 1D Hamiltonians\nThe function Quantica.gaps(h, µ) can be used to efficiently calculate the gaps respect to chemical potential µ at local band minima, but only for 1D Hamiltonian's for the moment. Similarly Quantica.decay_lengths(h, µ; reverse = false) will yield the decay lengths of the evanescent modes of h at energy µ (towards the positive direction, unless reverse = true). Both functions are unexported and experimental.","category":"page"},{"location":"tutorial/bandstructures/#Band-indexing-and-slicing","page":"Bandstructures","title":"Band indexing and slicing","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The individual subbands in a given b::Bandstructure can be obtained with b[inds] with inds::Integer or inds::Vector, just as if b where a normal AbstractVector. The extracted subbands can also be plotted directly. The following example has 12 subbands, of which we extract and plot the first and last","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.triangular() |> supercell(4) |> hopping(1) + onsite(r -> 4*rand());\n\njulia> b = bands(h, subdiv(0, 2π, 31), subdiv(0, 2π, 31))\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 12\n Vertices : 15376\n Edges : 44152\n Simplices : 28696\n\njulia> qplot(b, hide = (:nodes, :wireframe))\n\njulia> qplot(b[[1, end]], hide = (:nodes, :wireframe))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Extracting","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"For a band in a 2D Brillouin zone, we can also obtain the intersection of a bandstructure with a plane of constant energy ϵ=2 using the syntax b[(:,:,2)]. A section at fixed Bloch phase ϕ₁=0 (or mesh coordinate x₁=0 if mapping was used), can be obtained with b[(0,:,:)]. This type of band slicing can be generalized to higher dimensional bandstructures, or to more than one constrain (e.g. energy and/or a subset of Bloch phases). As an example, this would be the Fermi surface of a nearest-neighbor cubic-lattice Hamiltonian at Fermi energy µ = 0.2t","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> pts = subdiv(0, 2π, 41); b = LP.cubic() |> hopping(1) |> bands(pts, pts, pts)\nBandstructure{Float64,4,3}: 4D Bandstructure over a 3-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 68921\n Edges : 462520\n Simplices : 384000\n\njulia> qplot(b[(:, :, :, 0.2)], hide = (:nodes, :wireframe))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Fermi","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"warning: On simplex orientation of bandstructure slices\nThe above example showcases a current (cosmetic) limitation of the band slicing algorithm: it sometimes fails to align all faces of the resulting manifold to the same orientation. The dark and bright regions of the surface above reveals that approximately half of the faces in this case are facing inward and the rest outward.","category":"page"},{"location":"","page":"Home","title":"Home","text":"(Image: Quantica.jl logo)","category":"page"},{"location":"","page":"Home","title":"Home","text":"Quantica.jl is a Julia package for building generic tight-binding models and computing spectral and transport properties.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"julia> import Pkg; Pkg.add(\"Quantica\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"Quantica.jl requires Julia v1.9 or later. Some of its functionality, notably plotting, will become available only after using GLMakie, or some other plotting package from the Makie.jl family. Install GLMakie with","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> import Pkg; Pkg.add(\"GLMakie\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"Then, to begin using Quantica, just load it by doing","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using Quantica","category":"page"},{"location":"","page":"Home","title":"Home","text":"(and possibly also e.g. using GLMakie if you need to plot Quantica objects).","category":"page"},{"location":"#Asking-questions,-reporting-bugs","page":"Home","title":"Asking questions, reporting bugs","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"If you encounter problems, please read the tutorial and examples, your question is probably answered there. You can also check the docstring of each Quantica.jl function here or within the Julia REPL, by entering the function preceded by a ?, e.g. ?hamiltonian.","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you are still stuck, you may sometimes find me (@pablosanjose) at the Julia Slack or Julia Discourse.","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you believe you found a bug in Quantica.jl, please don't hesitate to file a GitHub issue, preferably with detailed instructions to reproduce it. Pull requests with fixes are also welcome!","category":"page"}] +[{"location":"advanced/meanfield/#Self-consistent-mean-field-problems","page":"Self-consistent mean fields","title":"Self-consistent mean-field problems","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Here we show how to solve interacting-electron problems in Quantica, approximated at the mean field level. A mean field is a collection of onsite and hopping terms that are added to a given h::AbstractHamiltonian, that depend on the density matrix ρ. Since ρ itself depends on h, this defines a self-consistent problem.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"If the mean field solution is dubbed Φ, the problem consists in finding a fixed point solution to the function Φ = M(Φ) for a certain function M that takes Φ, computes h with the added mean field onsite and hopping terms, computes the density matrix, and from that computes the new mean field Φ. To attack this problem we will employ non-spatial models and a new meanfield constructor.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Schematically the process is as follows:","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"We start from an AbstractHamiltonian that includes a non-interacting model model_0 and non-spatial model model_1 + model_2 with a mean field parameter, e.g. Φ,","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> model_0 = hopping(1); # a possible non-interacting model\n\njulia> model_1 = @onsite((i; Φ = zerofield) --> Φ[i]);\n\njulia> model_2 = @hopping((i, j; Φ = zerofield) -> Φ[i, j]);Fock\n\njulia> h = lat |> hamiltonian(model_0 + model_1 + model_2)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Here model_1 corresponds to Hartree and onsite-Fock mean field terms, while model_2 corresponds to inter-site Fock terms. The default value Φ = zerofield is an singleton object that represents no interactions, so model_1 and model_2 vanish by default.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"We build the GreenFunction of h with g = greenfunction(h, solver; kw...) using the GreenSolver of choice\nWe construct a M::MeanField object using M = meanfield(g; potential = pot, other_options...)\nHere pot(r) is the charge-charge interaction potential between electrons. We can also specify hopselector directives to define which sites interacts, adding e.g. selector = (; range = 2) to other_options, to make sites at distance 2 interacting. See meanfield docstring for further details.\nWe evaluate this M with Φ0 = M(µ, kBT; params...).\nThis computes the density matrix at specific chemical potential µ and temperature kBT, and for specific parameters of h (possibly including Φ). Then it computes the appropriate Hartree and Fock terms, and stores them in the returned Φ0::OrbitalSliceMatrix, where Φ0ᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ. In normal systems, these terms read\ntexthartree_i = Q sum_k v_H(r_i-r_k) texttr(rho_kkQ)\ntextfock_ij = -v_F(r_i-r_j) Q rho_ij Q\nwhere v_H and v_F are Hartree and Fock charge-charge interaction potentials (by default equal to pot), and the charge operator is Q (equal to the identity by default, but can be changed to implement e.g. spin-spin interactions).\nWhen computing Φ0 we don't specify Φ in params, so that Φ0 is evaluated using the non-interacting model, hence its name.\nThe self-consistent condition can be tackled naively by iteration-until-convergence,","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Φ0 = M(µ, kBT; params...)\nΦ1 = M(µ, KBT; Φ = Φ0, params...)\nΦ2 = M(µ, KBT; Φ = Φ1, params...)\n...","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"A converged solution Φ, if found, should satisfy the fixed-point condition","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Φ_sol ≈ M(µ, KBT; Φ = Φ_sol, params...)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Then, the self-consistent Hamiltonian is given by h(; Φ = Φ_sol, params...).","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"The key problem is to actually find the fixed point of the M function. The naive iteration above is not optimal, and often does not converge. To do a better job we should use a dedicated fixed-point solver.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"note: Superconducting systems\nSuperconducting (Nambu) Hamiltonians obey the same equations for the Hartree and Fock mean fields, with a proper definition of Q, and an extra 1/2 coefficient in the Hartree trace, see the meanfield doctring.","category":"page"},{"location":"advanced/meanfield/#Using-an-external-fixed-point-solver","page":"Self-consistent mean fields","title":"Using an external fixed-point solver","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"We now show how to approach such a fixed-point problem. We will employ an external library to solve generic fixed-point problems, and show how to make it work with Quantica MeanField objects efficiently. Many generic fixed-point solver backends exist. Here we use the SIAMFANLEquations.jl package. It provides a simple utility aasol(f, x0) that computes the solution of f(x) = x with initial condition x0 using Anderson acceleration. This is an example of how it works to compute the fixed point of function f(x) = 1 + atan(x)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> f!(x, x0) = (x .= 1 .+ atan.(x0))\n\njulia> m = 3; x0 = rand(3); vstore = rand(3, 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> aasol(f!, x0, m, vstore).solution\n3-element Vector{Float64}:\n 2.132267725272934\n 2.132267725272908\n 2.132267725284556","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"The package requires as input an in-place version f! of the function f, and the preallocation of some storage space vstore (see the aasol documentation). The package, as a few others, also requires the variable x and the initial condition x0 to be an AbstractArray (or a scalar, but we need the former for our use case), hence the broadcast dots above. In our case we will therefore need to translate back and forth from an Φ::OrbitalSliceMatrix to a real vector x to pass it to aasol. This translation is achieved using Quantica's serialize/deserialize funcionality.","category":"page"},{"location":"advanced/meanfield/#Using-Serializers-with-fixed-point-solvers","page":"Self-consistent mean fields","title":"Using Serializers with fixed-point solvers","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"With the serializer functionality we can build a version of the fixed-point function f that operates on real vectors. Let's take a 1D Hamiltonian with a sawtooth potential, and build a Hartree mean field (note the fock = nothing keyword)","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> h = LP.linear() |> supercell(4) |> onsite(r->r[1]) - hopping(1) + @onsite((i; phi = zerofield) --> phi[i]);\n\njulia> M = meanfield(greenfunction(h); onsite = 1, selector = (; range = 0), fock = nothing)\nMeanField{ComplexF64} : builder of Hartree-Fock-Bogoliubov mean fields\n Charge type : scalar (ComplexF64)\n Hartree pairs : 4\n Mean field pairs : 4\n Nambu : false\n\njulia> Φ0 = M(0.0, 0.0);\n\njulia> function f!(x, x0, (M, Φ0))\n Φ = M(0.0, 0.0; phi = deserialize(Φ0, x0))\n copy!(x, serialize(Φ))\n return x\n end;","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Then we can proceed as in the f(x) = 1 + atan(x) example","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> m = 2; x0 = serialize(Φ0); vstore = rand(length(x0), 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> x = aasol(f!, x0, m, vstore; pdata = (M, Φ0)).solution\n4-element Vector{ComplexF64}:\n 0.5658185030962436 + 0.0im\n 0.306216109313951 + 0.0im\n 0.06696362342872919 + 0.0im\n 0.06100176416107613 + 0.0im\n\njulia> h´ = h(; phi = deserialize(Φ0, x))\nHamiltonian{Float64,1,1}: Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 4 × 4\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 4\n Hoppings : 8\n Coordination : 2.0\n\njulia> h´[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 0.565819+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 1.30622+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.06696+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 3.061+0.0im","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Note that the content of pdata is passed by aasol as a third argument to f!. We use this to pass the serializer s and U parameter to use.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"note: Bring your own fixed-point solver!\nNote that fixed-point calculations can be tricky, and the search algorithm can have a huge impact in convergence (if the problem converges at all!). For this reason, Quantica.jl does not provide built-in fixed-point routines, only the functionality to write functions such as f above. Numerous packages exist for fixed-point computations in julia. Check NonlinearSolve.jl for one prominent metapackage.","category":"page"},{"location":"advanced/meanfield/#GreenSolvers-without-support-for-ParametricHamiltonians","page":"Self-consistent mean fields","title":"GreenSolvers without support for ParametricHamiltonians","text":"","category":"section"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"Some GreenSolver's, like GS.Spectrum or GS.KPM, do not support ParametricHamiltonians. In such cases, the approach above will fail, since it will not be possible to build g before knowing phi. In such cases one would need to rebuild the meanfield object at each step of the fixed-point solver. This is one way to do it.","category":"page"},{"location":"advanced/meanfield/","page":"Self-consistent mean fields","title":"Self-consistent mean fields","text":"julia> using SIAMFANLEquations\n\njulia> h = LP.linear() |> supercell(4) |> supercell |> onsite(1) - hopping(1) + @onsite((i; phi) --> phi[i]);\n\njulia> M´(phi = zerofield) = meanfield(greenfunction(h(; phi), GS.Spectrum()); onsite = 1, selector = (; range = 0), fock = nothing)\nM´ (generic function with 3 methods)\n\njulia> Φ0 = M´()(0.0, 0.0);\n\njulia> function f!(x, x0, (M´, Φ0))\n Φ = M´(deserialize(Φ0, x0))(0.0, 0.0)\n copy!(x, serialize(Φ))\n return x\n end;\n\njulia> m = 2; x0 = serialize(Φ0); vstore = rand(length(x0), 3m+3); # order m, initial condition x0, and preallocated space vstore\n\njulia> x = aasol(f!, x0, m, vstore; pdata = (M´, Φ0)).solution\n4-element Vector{ComplexF64}:\n 0.15596283661234628 + 0.0im\n 0.34403716338765444 + 0.0im\n 0.34403716338765344 + 0.0im\n 0.15596283661234572 + 0.0im","category":"page"},{"location":"advanced/nonspatial/#Non-spatial-models","page":"Non-spatial models","title":"Non-spatial models","text":"","category":"section"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"As briefly mentioned when discussing parametric models and modifiers, we have a special syntax that allows models to depend on sites directly, instead of on their spatial location. We call these non-spatial models. A simple example, with an onsite energy proportional to the site index","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> model = @onsite((i; p = 1) --> ind(i) * p)\nParametricModel: model with 1 term\n ParametricOnsiteTerm{ParametricFunction{1}}\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n Argument type : non-spatial\n Parameters : [:p]","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"or a modifier that changes a hopping between different cells","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> modifier = @hopping!((t, i, j; dir = 1) --> (cell(i) - cell(j))[dir])\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : non-spatial\n Parameters : [:dir]","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Note that we use the special syntax --> instead of ->. This indicates that the positional arguments of the function, here called i and j, are no longer site positions as up to now. These i, j are non-spatial arguments, as noted by the Argument type property shown above. Instead of a position, a non-spatial argument i represent an individual site, whose index is ind(i), its position is pos(i) and the cell it occupies on the lattice is cell(i).","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Technically i is of type CellSitePos, which is an internal type not meant for the end user to instantiate. One special property of this type, however, is that it can efficiently index OrbitalSliceArrays. We can use this to build a Hamiltonian that depends on an observable, such as a densitymatrix. A simple example of a four-site chain with onsite energies shifted by a potential proportional to the local density on each site:","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"julia> h = LP.linear() |> onsite(2) - hopping(1) |> supercell(4) |> supercell;\n\njulia> h(SA[])\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 2.0+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 2.0+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.0+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 2.0+0.0im\n\njulia> g = greenfunction(h, GS.Spectrum());\n\njulia> ρ0 = densitymatrix(g[])(0.5, 0) ## density matrix at chemical potential `µ=0.5` and temperature `kBT = 0` on all sites\n4×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.138197+0.0im 0.223607+0.0im 0.223607+0.0im 0.138197+0.0im\n 0.223607+0.0im 0.361803+0.0im 0.361803+0.0im 0.223607+0.0im\n 0.223607+0.0im 0.361803+0.0im 0.361803+0.0im 0.223607+0.0im\n 0.138197+0.0im 0.223607+0.0im 0.223607+0.0im 0.138197+0.0im\n\njulia> hρ = h |> @onsite!((o, i; U = 0, ρ = ρ0) --> o + U * ρ[i])\nParametricHamiltonian{Float64,1,0}: Parametric Hamiltonian on a 0D Lattice in 1D space\n Bloch harmonics : 1\n Harmonic size : 4 × 4\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 4\n Hoppings : 6\n Coordination : 1.5\n Parameters : [:U, :ρ]\n\njulia> hρ(SA[]; U = 1, ρ = ρ0)\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:\n 2.1382+0.0im -1.0+0.0im ⋅ ⋅\n -1.0+0.0im 2.3618+0.0im -1.0+0.0im ⋅\n ⋅ -1.0+0.0im 2.3618+0.0im -1.0+0.0im\n ⋅ ⋅ -1.0+0.0im 2.1382+0.0im","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"Note the ρ[i] above. This indexes ρ at site i. For a multiorbital hamiltonian, this will be a matrix (the local density matrix on each site i). Here it is just a number, either 0.138197 (sites 1 and 4) or 0.361803 (sites 2 and 3).","category":"page"},{"location":"advanced/nonspatial/","page":"Non-spatial models","title":"Non-spatial models","text":"tip: Sparse vs dense\nThe method explained above to build a Hamiltonian hρ using --> supports all the SiteSelector and HopSelector functionality of conventional models. Therefore, although the density matrix computed above is dense, its application to the Hamiltonian is sparse: it only touches the onsite matrix elements in this case.","category":"page"},{"location":"tutorial/greenfunctions/#GreenFunctions","page":"GreenFunctions","title":"GreenFunctions","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Up to now we have seen how to define Lattices, Models, Hamiltonians and Bandstructures. Most problems require the computation of different physical observables for these objects, e.g. the local density of states or various transport coefficients. We reduce this general problem to the computation of the retarded Green function","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"G^r_ij(omega) = langle i(omega-H-Sigma(omega))^-1jrangle","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"where i, j are orbitals, H is the (possibly infinite) Hamiltonian matrix, and Σ(ω) is the self-energy coming from any coupling to other systems (typically described by their own AbstractHamiltonian).","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We split the problem of computing Gʳᵢⱼ(ω) of a given h::AbstractHamiltonian into four steps:","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Attach self-energies to h using the command oh = attach(h, args...). This produces a new object oh::OpenHamiltonian with a number of Contacts, numbered 1 to N\nUse g = greenfunction(oh, solver) to build a g::GreenFunction representing Gʳ (at arbitrary ω and i,j), where oh::OpenHamiltonian and solver::AbstractGreenSolver (see GreenSolvers below for available solvers)\nEvaluate gω = g(ω; params...) at fixed energy ω and model parameters, which produces a gω::GreenSolution\nSlice gω[sᵢ, sⱼ] or gω[sᵢ] == gω[sᵢ, sᵢ] to obtain Gʳᵢⱼ(ω) as a flat matrix, where sᵢ, sⱼ are either site selectors over sites spanning orbitals i,j, integers denoting contacts, 1 to N, or : denoting all contacts merged together.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: GreenSlice vs. GreenSolution\nThe two last steps can be interchanged, by first obtaining a gs::GreenSlice with gs = g[sᵢ, sⱼ] and then obtaining the Gʳᵢⱼ(ω) matrix with gs(ω; params...).","category":"page"},{"location":"tutorial/greenfunctions/#A-simple-example","page":"GreenFunctions","title":"A simple example","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Here is a simple example of the Green function of a 1D lead with two sites per unit cell, a boundary at cell = 0, and with no attached self-energies for simplicity","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> hlead = LP.square() |> supercell((1,0), region = r -> 0 <= r[2] < 2) |> hopping(1);\n\njulia> glead = greenfunction(hlead, GreenSolvers.Schur(boundary = 0))\nGreenFunction{Float64,2,1}: Green function of a Hamiltonian{Float64,2,1}\n Solver : AppliedSchurGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n Hamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> gω = glead(0.2) # we first fix energy to ω = 0.2\nGreenSolution{Float64,2,1}: Green function at arbitrary positions, but at a fixed energy\n\njulia> gω[cells = 1:2] # we now ask for the Green function between orbitals in the first two unit cells to the righht of the boundary\n4×4 Matrix{ComplexF64}:\n 0.1-0.858258im -0.5-0.0582576im -0.48-0.113394im -0.2+0.846606im\n -0.5-0.0582576im 0.1-0.858258im -0.2+0.846606im -0.48-0.113394im\n -0.48-0.113394im -0.2+0.846606im 0.104-0.869285im 0.44+0.282715im\n -0.2+0.846606im -0.48-0.113394im 0.44+0.282715im 0.104-0.869285im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that the result is a 4 x 4 matrix, because there are 2 orbitals (one per site) in each of the two unit cells. Note also that the GreenSolvers.Schur used here allows us to compute the Green function between distant cells with little overhead","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> @time gω[cells = 1:2];\n 0.000067 seconds (70 allocations: 6.844 KiB)\n\njulia> @time gω[cells = (SA[10], SA[100000])];\n 0.000098 seconds (229 allocations: 26.891 KiB)","category":"page"},{"location":"tutorial/greenfunctions/#GreenSolvers","page":"GreenFunctions","title":"GreenSolvers","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The currently implemented GreenSolvers (abbreviated as GS) are the following","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.SparseLU()\nFor bounded (L=0) AbstractHamiltonians. Default for L=0.\nUses a sparse LU factorization to compute the inverse of ⟨i|ω - H - Σ(ω)|j⟩, where Σ(ω) is the self-energy from the contacts.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Spectrum(; spectrum_kw...)\nFor bounded (L=0) Hamiltonians. This solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first.\nUses a diagonalization of H, obtained with spectrum(H; spectrum_kw...), to compute the G⁰ᵢⱼ using the Lehmann representation ∑ₖ⟨i|ϕₖ⟩⟨ϕₖ|j⟩/(ω - ϵₖ). Any eigensolver supported by spectrum can be used here. If there are contacts, it dresses G⁰ using a T-matrix approach, G = G⁰ + G⁰TG⁰.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.KPM(order = 100, bandrange = missing, kernel = I)\nFor bounded (L=0) Hamiltonians, and restricted to sites belonging to contacts (see the section on Contacts).\nIt precomputes the Chebyshev momenta, and incorporates the contact self energy with a T-matrix approach.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Schur(boundary = Inf)\nFor 1D (L=1) AbstractHamiltonians with only nearest-cell coupling. Default for L=1.\nUses a deflating Generalized Schur (QZ) factorization of the generalized eigenvalue problem to compute the unit-cell self energies. The Dyson equation then yields the Green function between arbitrary unit cells, which is further dressed using a T-matrix approach if the lead has any attached self-energy.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"GS.Bands(bandsargs...; boundary = missing, bandskw...)\nFor unbounded (L>0) Hamiltonians.\nIt precomputes a bandstructure b = bands(h, bandsargs...; kw..., split = false) and then uses analytic expressions for the contribution of each subband simplex to the GreenSolution. If boundary = dir => cell_pos, it takes into account the reflections on an infinite boundary perpendicular to Bravais vector number dir, so that all sites with cell index c[dir] <= cell_pos are removed. Contacts are incorporated using a T-matrix approach.\nTo retrieve the bands from a g::GreenFunction that used the GS.Bands solver, we may use bands(g).","category":"page"},{"location":"tutorial/greenfunctions/#Attaching-Contacts","page":"GreenFunctions","title":"Attaching Contacts","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"A self energy Σ(ω) acting of a finite set of sites of h (i.e. on a LatticeSlice of lat = lattice(h)) can be incorporated using the attach command. This defines a new Contact in h. The general syntax is oh = attach(h, args...; sites...), where the sites directives define the Contact LatticeSlice (lat[siteselector(; sites...)]), and args can take a number of forms.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The supported attach forms are the following","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Generic self-energy\nattach(h, gs::GreenSlice, coupling::AbstractModel; sites...)\nThis is the generic form of attach, which couples some sites i of a g::Greenfunction (defined by the slice gs = g[i]), to sites of h using a coupling model. This results in a self-energy Σ(ω) = V´⋅gs(ω)⋅V on h sites, where V and V´ are couplings matrices given by coupling.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Dummy self-energy\nattach(h, nothing; sites...)\nThis form merely defines a new contact on the specified sites, but adds no actual self-energy to it. It is meant as a way to refer to some sites of interest using the g[i::Integer] slicing syntax for GreenFunctions, where i is the contact index.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Model self-energy\nattach(h, model::AbstractModel; sites...)\nThis form defines a self-energy Σᵢⱼ(ω) in terms of model, which must be composed purely of parametric terms (@onsite and @hopping) that have ω as first argument, as in e.g. @onsite((ω, r) -> Σᵢᵢ(ω, r)) or @hopping((ω, r, dr) -> Σᵢⱼ(ω, r, dr)). This is a modellistic approach, wherein the self-energy is not computed from the properties of another AbstractHamiltonian, but rather has an arbitrary form defined by the user.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Matched lead self-energy\nattach(h, glead::GreenFunction; reverse = false, transform = identity, sites...)\nHere glead is a GreenFunction of a 1D lead, possibly with a boundary.\nWith this syntax sites must select a number of sites in h whose position match (after applying transform to them and modulo an arbitrary displacement) the sites in the unit cell of glead. Then, the coupling between these and the first unit cell of glead on the positive side of the boundary will be the same as between glead unitcells, i.e. V = hlead[(1,)], where hlead = hamiltonian(glead).\nIf reverse == true, the lead is reversed before being attached, so that h is coupled through V = hlead[(-1,)] to the first unitcell on the negative side of the boundary. If there is no boundary, the cell = 0 unitcell of the glead is used.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Generic lead self-energy\nattach(h, glead::GreenFunction, model::AbstractModel; reverse = false, transform = identity, sites...)\nThe same as above, but without any restriction on sites. The coupling between these and the first unit cell of glead (transformed by transform) is constructed using model::TightbindingModel. The \"first unit cell\" is defined as above.","category":"page"},{"location":"tutorial/greenfunctions/#A-more-advanced-example","page":"GreenFunctions","title":"A more advanced example","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Let us define the classical example of a multiterminal mesoscopic junction. We choose a square lattice, and a circular central region of radius 10, with four leads of width 5 coupled to it at right angles.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We first define a single lead Greenfunction and the central Hamiltonian","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> glead = LP.square() |> onsite(4) - hopping(1) |> supercell((1, 0), region = r -> abs(r[2]) <= 5/2) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> hcentral = LP.square() |> onsite(4) - hopping(1) |> supercell(region = RP.circle(10) | RP.rectangle((22, 5)) | RP.rectangle((5, 22)));","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"The two rectangles overlayed on the circle above create the stubs where the leads will be attached:","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Central","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We now attach glead four times using the Matched lead syntax","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> Rot = r -> SA[0 -1; 1 0] * r; # 90º rotation function\n\njulia> g = hcentral |>\n attach(glead, region = r -> r[1] == 11) |>\n attach(glead, region = r -> r[1] == -11, reverse = true) |>\n attach(glead, region = r -> r[2] == 11, transform = Rot) |>\n attach(glead, region = r -> r[2] == -11, reverse = true, transform = Rot) |>\n greenfunction\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 4\n Contact solvers : (SelfEnergySchurSolver, SelfEnergySchurSolver, SelfEnergySchurSolver, SelfEnergySchurSolver)\n Contact sizes : (5, 5, 5, 5)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 353 × 353\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 1320\n Coordination : 3.73938\n\njulia> qplot(g, children = (; selector = siteselector(; cells = 1:5), sitecolor = :blue))","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Multiterminal","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that since we did not specify the solver in greenfunction, the L=0 default GS.SparseLU() was taken.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We can also visualize glead, which is defined on a 1D lattice with a boundary. Boundary cells are shown by default in red","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: The GreenFunction <-> AbstractHamiltonian relation\nIts important un appreciate that a g::GreenFunction represents the retarded Green function between sites in a given AbstractHamiltonian, but not on sites of the coupled AbstractHamiltonians of its attached self-energies. Therefore, gcentral above cannot yield observables in the leads (blue sites above), only on the red sites. To obtain observables in a given lead, its GreenFunction must be constructed, with an attached self-energy coming from the central region plus the other three leads.","category":"page"},{"location":"tutorial/greenfunctions/#Slicing-and-evaluation","page":"GreenFunctions","title":"Slicing and evaluation","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"As explained above, a g::GreenFunction represents a Green function of an OpenHamiltonian (i.e. AbstractHamiltonian with zero or more self-energies), but it does so for any energy ω or lattice sites.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"- To specify `ω` (plus any parameters `params` in the underlying `AbstractHamiltonian`) we use the syntax `g(ω; params...)`, which yields an `gω::GreenSolution`\n- To specify source (`sⱼ`) and drain (`sᵢ`) sites we use the syntax `g[sᵢ, sⱼ]` or `g[sᵢ] == g[sᵢ,sᵢ]`, which yields a `gs::GreenSlice`. `sᵢ` and `sⱼ` can be `SiteSelectors(; sites...)`, or an integer denoting a specific contact (i.e. sites with an attached self-energy) or `:` denoting all contacts merged together.\n- If we specify both of the above we get the Green function between the orbitals of the specified sites at the specified energy, in the form of an `OrbitalSliceMatrix`, which is a special `AbstractMatrix` that knows about the orbitals in the lattice over which its matrix elements are defined.","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Let us see this in action using the example from the previous section","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g[1, 3]\nGreenSlice{Float64,2,0}: Green function at arbitrary energy, but at a fixed lattice positions\n\njulia> g(0.2)\nGreenSolution{Float64,2,0}: Green function at arbitrary positions, but at a fixed energy\n\njulia> g(0.2)[1, 3]\n5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -2.56906+0.000123273im -4.28767+0.00020578im -4.88512+0.000234514im -4.28534+0.00020578im -2.5664+0.000123273im\n -4.28767+0.00020578im -7.15613+0.00034351im -8.15346+0.000391475im -7.15257+0.00034351im -4.2836+0.000205781im\n -4.88512+0.000234514im -8.15346+0.000391475im -9.29002+0.000446138im -8.14982+0.000391476im -4.88095+0.000234514im\n -4.28534+0.00020578im -7.15257+0.00034351im -8.14982+0.000391476im -7.14974+0.000343511im -4.28211+0.000205781im\n -2.5664+0.000123273im -4.2836+0.000205781im -4.88095+0.000234514im -4.28211+0.000205781im -2.56469+0.000123273im\n\njulia> g(0.2)[siteselector(region = RP.circle(1, (0.5, 0))), 3]\n2×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.0749214+3.15744e-8im 0.124325+5.27948e-8im 0.141366+6.01987e-8im 0.124325+5.27948e-8im 0.0749214+3.15744e-8im\n -0.374862+2.15287e-5im -0.625946+3.5938e-5im -0.712983+4.09561e-5im -0.624747+3.59379e-5im -0.37348+2.15285e-5im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: Fixing parameters\nIn the same way we can fix all parameters of a h::ParametricHamiltonian with h´=h(;params...) (which produces a h´::Hamiltonian without any parametric dependencies), we can similarly fix all parameters in a g::GreenFunction (or g::GreenSlice) with g(; params...), which produces a new GreenFunction (or GreenSlice). Note that, like in the case of h, this fixes all parameters. Any parameter that is not specify will be fixed to its default value.","category":"page"},{"location":"tutorial/greenfunctions/#Diagonal-slices","page":"GreenFunctions","title":"Diagonal slices","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"There is a special form of slicing that requests just the diagonal of a given g[sᵢ] == g[sᵢ,sᵢ]. It uses the syntax g[diagonal(sᵢ)]. Let us see it in action in a multiorbital example in 2D","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g = HP.graphene(a0 = 1, t0 = 1, orbitals = 2) |> greenfunction\nGreenFunction{Float64,2,2}: Green function of a Hamiltonian{Float64,2,2}\n Solver : AppliedBandsGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n Hamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> g(0.5)[diagonal(cells = (0, 0))]\n4-element OrbitalSliceVector{Vector{ComplexF64}}:\n -0.3497363468480622 - 0.3118358260294266im\n -0.3497363468271048 - 0.31183582602942655im\n -0.3497363468402952 - 0.31183582602942667im\n -0.34973634686125243 - 0.3118358260294267im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that we get an OrbitalSliceVector, which is equal to the diagonal diag(g(0.5)[cells = (0, 0)]). Like the g OrbitalSliceMatrix, this vector is resolved in orbitals, of which there are two per site and four per unit cell in this case. Using diagonal(sᵢ; kernel = K) we can collect all the orbitals of different sites, and compute tr(g[site, site] * K) for a given matrix K. This is useful to obtain spectral densities. In the above example, and interpreting the two orbitals per site as the electron spin, we could obtain the spin density along the x axis, say, using σx = SA[0 1; 1 0] as kernel,","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> g(0.5)[diagonal(cells = (0, 0), kernel = SA[0 1; 1 0])]\n2-element OrbitalSliceVector{Vector{ComplexF64}}:\n 4.26186044627701e-12 - 2.2846013280115095e-17im\n -4.261861877528737e-12 + 1.9177925470610777e-17im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"which is zero in this spin-degenerate case","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"tip: Slicing `OrbitalSliceArray`s\nAn v::OrbitalSliceVector and m::OrbitalSliceMatrix are both a::OrbitalSliceArray, and wrap conventional arrays, with e.g. conventional axes. They also provide, however, orbaxes(a), which are a tuple of OrbitalSliceGrouped. These are LatticeSlices that represent orbitals grouped by sites. They allow an interesting additional functionality. You can index v[sitelector(...)] or m[rowsiteselector, colsiteselector] to obtain a new OrbitalSliceArray of the selected rows and cols. The full machinery of siteselector applies. One can also use a lower-level v[sites(cell_index, site_indices)] to obtain an unwrapped AbstractArray, without building new orbaxes. See OrbitalSliceArray for further details.","category":"page"},{"location":"tutorial/greenfunctions/#Visualizing-a-Green-function","page":"GreenFunctions","title":"Visualizing a Green function","text":"","category":"section"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"We can use qplot to visualize a GreenSolution in space. Here we define a bounded square lattice with an interesting shape, and attach a model self-energy to the right. Then we compute the Green function from each orbital in the contact to any other site in the lattice, and compute the norm over contact sites. The resulting vector is used as a shader for the color and radius of sites when plotting the system","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"julia> h = LP.square() |> onsite(4) - hopping(1) |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1]))));\n\njulia> g = h |> attach(@onsite(ω -> -im), region = r -> r[1] ≈ 47) |> greenfunction;\n\njulia> gx1 = sum(abs2, g(0.1)[siteselector(), 1], dims = 2);\n\njulia> qplot(h, hide = :hops, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"\"Green","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"warning: Caveat for multiorbital systems\nSince, currently, g(ω)[sᵢ, sⱼ] yields a Matrix over orbitals (instead of over sites), the above example requires single-orbital sites to work. In the future we will probably introduce a way to slice a GreenSolution over sites, similar to the way diagonal works. For the moment, one can use observables like ldos for visualization (see next section), which are all site-based by default.","category":"page"},{"location":"tutorial/lattices/#Lattices","page":"Lattices","title":"Lattices","text":"","category":"section"},{"location":"tutorial/lattices/#Constructing-a-Lattice-from-scratch","page":"Lattices","title":"Constructing a Lattice from scratch","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Consider a lattice like graphene's. It has two sublattices, A and B, forming a 2D honeycomb pattern in space. The position of site A and B inside the unitcell are [0, -a0/(2√3)] and [0, a0/(2√3)], respectively. The Bravais vectors are A₁, A₂ = a0 * [± cos(π/3), sin(π/3)]. If we set the lattice constant to a0 = √3 (so the carbon-carbon distance is 1), one way to build this lattice in Quantica.jl would be","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> A₁, A₂ = √3 .* (cos(π/3), sin(π/3)),\n √3 .* (-cos(π/3), sin(π/3));\n\njulia> sA, sB = sublat((0, -1/2), name = :A),\n sublat((0, 1/2), name = :B);\n\njulia> lattice(sA, sB, bravais = (A₁, A₂))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.866025, 1.5], [-0.866025, 1.5]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Tuple, SVector and SMatrix\nNote that we have used Tuples, such as (0, 1/2) instead of Vectors, like [0, 1/2]. In Julia small-length Tuples are much more efficient as containers than Vectors, since their length is known and fixed at compile time. Static vectors (SVector) and matrices (SMatrix) are also available to Quantica, which are just as efficient as Tuples, and they also implement linear algebra operations. They may be entered as e.g. SA[0, 1/2] and SA[1 0; 0 1], respectively. For efficiency, always use Tuple, SVector and SMatrix in Quantica.jl where possible.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"If we don't plan to address the two sublattices individually, we could also fuse them into one, like","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = lattice(sublat((0, 1/2), (0, -1/2)), bravais = (A₁, A₂))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.866025, 1.5], [-0.866025, 1.5]]\n Sublattices : 1\n Names : (:A,)\n Sites : (2,) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"This lattice has type Lattice{T,E,L}, with T = Float64 the numeric type of position coordinates, E = 2 the dimension of embedding space, and L = 2 the number of Bravais vectors (i.e. the lattice dimension). Both T and E, and even the Sublat names can be overridden when creating a lattice. One can also provide the Bravais vectors as a matrix, with each Aᵢ as a column.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> Amat = √3 * SA[-cos(π/3) cos(π/3); sin(π/3) sin(π/3)];\n\njulia> lat´ = lattice(sA, sB, bravais = Amat, type = Float32, dim = 3, names = (:C, :D))\nLattice{Float32,3,2} : 2D lattice in 3D space\n Bravais vectors : Vector{Float32}[[-0.866025, 1.5, 0.0], [0.866025, 1.5, 0.0]]\n Sublattices : 2\n Names : (:C, :D)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Advanced: `dim = Val(E)` vs. `dim = E`\nFor the dim keyword above we can alternatively use dim = Val(3), which is slightly more efficient, because the value is encoded as a type. This is a \"Julia thing\" (related to the concept of type stability), and can be ignored upon a first contact with Quantica.jl.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"One can also convert an existing lattice like the above to have a different type, embedding dimension, Bravais vectors and Sublat names with lattice(lat; kw...). For example","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat´´ = lattice(lat´, type = Float16, dim = 2, names = (:Boron, :Nitrogen))\nLattice{Float16,2,2} : 2D lattice in 2D space\n Bravais vectors : Vector{Float16}[[-0.866, 1.5], [0.866, 1.5]]\n Sublattices : 2\n Names : (:Boron, :Nitrogen)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"A list of site positions in a lattice lat can be obtained with sites(lat), or sites(lat, sublat) to restrict to a specific sublattice","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> sites(lat´´)\n2-element Vector{SVector{2, Float16}}:\n [0.0, -0.5]\n [0.0, 0.5]\n\njulia> sites(lat´´, :Nitrogen)\n1-element view(::Vector{SVector{2, Float16}}, 2:2) with eltype SVector{2, Float16}:\n [0.0, 0.5]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Similarly, the Bravais matrix of a lat can be obtained with bravais_matrix(lat).","category":"page"},{"location":"tutorial/lattices/#Lattice-presets","page":"Lattices","title":"Lattice presets","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Quantica.jl provides a range of presets. A preset is a pre-built object of some type. In particular we have Lattice presets, defined in the submodule LatticePresets (also called LP for convenience), that include a number of classical lattices in different dimensions:","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"LP.linear: linear 1D lattice\nLP.square: square 2D lattice\nLP.honeycomb: honeycomb 2D lattice\nLP.cubic: cubic 3D lattice\nLP.bcc: body-centered cubic 3D lattice\nLP.fcc: face-centered cubic 3D lattice","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To obtain a lattice from a preset one simply calls it, e.g. LP.honecyomb(; kw...). One can modify any of these LatticePresets by passing a bravais, type, dim or names keyword. One can also use a new keyword a0 for the lattice constant (a0 = 1 by default). The lattice lat´´ above can thus be also obtained with","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat´´ = LP.honeycomb(a0 = √3, type = Float16, names = (:Boron, :Nitrogen))\nLattice{Float16,2,2} : 2D lattice in 2D space\n Bravais vectors : Vector{Float16}[[0.866, 1.5], [-0.866, 1.5]]\n Sublattices : 2\n Names : (:Boron, :Nitrogen)\n Sites : (1, 1) --> 2 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Quantica's Presets library\nQuantica comes with four submodules that provide different kinds of presets: LatticePresets (LP), HamiltonianPresets (HP), RegionPresets (RP) and ExternalPresets (EP). LP provides a collection of standard lattices, HP some premade model Hamiltonians such as HP.graphene or HP.twisted_bilayer_graphene, RP some geometric regions such as RP.circle or RP.cuboid, and EP some importers of externally produced objects such as EP.wannier90 to import Wannier90 files (see Advanced for details on the latter). This library of presets is expected to grow with time. The docstring for the submodule or the preset function can be queried for a description of the available options.","category":"page"},{"location":"tutorial/lattices/#Visualization","page":"Lattices","title":"Visualization","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To produce an interactive visualization of Lattices or other Quantica.jl object you need to load GLMakie.jl, CairoMakie.jl or some other plotting backend from the Makie repository (i.e. do using GLMakie, see also Installation). Then, a number of new plotting functions will become available. The main one is qplot. A Lattice is represented, by default, as the sites in a unitcell plus the Bravais vectors.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> using GLMakie\n\njulia> lat = LP.honeycomb()\n\njulia> qplot(lat, hide = nothing)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"Honeycomb","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"qplot accepts a large number of keywords to customize your plot. In the case of lattice, most of these are passed over to the function plotlattice, specific to Lattices and Hamiltonians. In the case above, hide = nothing means \"don't hide any element of the plot\". See the qplot and plotlattice docstrings for details.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: GLMakie.jl vs CairoMakie.jl\nGLMakie.jl is optimized for interactive GPU-accelerated, rasterized plots. If you need to export to PDF for publications or display plots inside a Jupyter notebook, use CairoMakie.jl instead, which in general renders non-interactive, but vector-based plots.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: User-defined defaults for `qplot`\nThe command qplotdefaults(; axis, figure) can be used to define the default value of figure and axis keyword arguments of qplot. Example: to fix the size of all subsequent plots, do qplotdefaults(; figure = (size = (1000, 1000),)).","category":"page"},{"location":"tutorial/lattices/#siteselectors","page":"Lattices","title":"SiteSelectors","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"A central concept in Quantica.jl is that of a \"selector\". There are two types of selectors, SiteSelectors and HopSelectors. SiteSelectors are a set of directives or rules that define a subset of its sites. SiteSelector rules are defined through three keywords:","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"region: a boolean function of allowed site positions r.\nsublats: allowed sublattices of selected sites\ncells: allowed cell indices of selected sites","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Similarly, HopSelectors can be used to select a number of site pairs, and will be used later to define hoppings in tight-binding models (see further below).","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"As an example, let us define a SiteSelector that picks all sites belonging to the :B sublattice of a given lattice within a circle of radius 10","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> s = siteselector(region = r -> norm(r) <= 10, sublats = :B)\nSiteSelector: a rule that defines a finite collection of sites in a lattice\n Region : Function\n Sublattices : B\n Cells : any","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Note that this selector is defined independently of the lattice. To apply it to a lattice lat we do lat[s], which results in a LatticeSlice (i.e. a finite portion, or slice, of lat)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = LP.honeycomb(); lat[s]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 363\n Cell range : ([-11, -11], [11, 11])\n Total sites : 363","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"The Cell range above are the corners of a bounding box in cell-index space that contains all unit cell indices with at least one selected site.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Let's plot it","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> qplot(lat[s], hide = ())","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"A","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: qplot selector\nThe above qplot(lat[s]) can also be written as qplot(lat, selector = s), which will be useful when plotting AbstractHamiltonians.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: Sites of a LatticeSlice\nCollect the site positions of a LatticeSlice into a vector with collect(sites(ls)). If you do sites(ls) instead, you will get a lazy generator that can be used to iterate efficiently among site positions without allocating them in memory.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Apart from region and sublats we can also restrict the unitcells by their cell index. For example, to select all sites in unit cells within the above bounding box we can do","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> s´ = siteselector(cells = CartesianIndices((-11:11, -11:11)))\nSiteSelector: a rule that defines a finite collection of sites in a lattice\n Region : any\n Sublattices : any\n Cells : CartesianIndices((-11:11, -11:11))\n\njulia> lat[s´]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 529\n Cell range : ([-11, -11], [11, 11])\n Total sites : 1058","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can often omit constructing the SiteSelector altogether by using the keywords directly","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> ls = lat[cells = n -> 0 <= n[1] <= 2 && abs(n[2]) < 3, sublats = :A]\nLatticeSlice{Float64,2,2} : collection of subcells for a 2D lattice in 2D space\n Cells : 15\n Cell range : ([0, -2], [2, 2])\n Total sites : 15","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Selectors are very expressive and powerful. Do check siteselector and hopselector docstrings for more details.","category":"page"},{"location":"tutorial/lattices/#Transforming-lattices","page":"Lattices","title":"Transforming lattices","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can transform lattices using supercell, reverse, transform, translate.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"As a periodic structure, the choice of the unitcell in an unbounded lattice is, to an extent, arbitrary. Given a lattice lat we can obtain another with a unit cell 3 times larger with supercell(lat, 3)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = supercell(LP.honeycomb(), 3)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 2.598076], [-1.5, 2.598076]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (9, 9) --> 18 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"More generally, given a lattice lat with Bravais matrix Amat = bravais_matrix(lat), we can obtain a larger one with Bravais matrix Amat´ = Amat * S, where S is a square matrix of integers. In the example above, S = SA[3 0; 0 3]. The columns of S represent the coordinates of the new Bravais vectors in the basis of the old Bravais vectors. A more general example with e.g. S = SA[3 1; -1 2] can be written either in terms of S or of its columns","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> supercell(lat, SA[3 1; -1 2]) == supercell(lat, (3, -1), (1, 2))\ntrue","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"We can also use supercell to reduce the number of Bravais vectors, and hence the lattice dimensionality. To construct a new lattice with a single Bravais vector A₁´ = 3A₁ - A₂, just omit the second one","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> supercell(lat, (3, -1))\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[6.0, 5.196152]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (27, 27) --> 54 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Its important to note that the lattice will be bounded along directions different from the specified Bravais vectors. With the syntax above, the new unitcell will be minimal. We may however define how many sites to include in the new unitcell by adding a SiteSelector directive to be applied in the non-periodic directions. For example, to create a 10 * a0 wide, honeycomb nanoribbon we can do","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> lat = supercell(LP.honeycomb(), (1,-1), region = r -> -5 <= r[2] <= 5)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 0.0]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (12, 12) --> 24 total per unit cell\n\njulia> qplot(lat[cells = -7:7])","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"\"Honeycomb","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"tip: No need to build selectors explicitly\nNote that we we didn't build a siteselector(region = ...) object to pass it to supercell. Instead, as shown above, we passed the corresponding keywords directly to supercell, which then takes care to build the selector internally.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To simply reverse the direction of the Bravais vectors of a lattice, while leaving the site positions unchanged, use reverse (or reverse! to do it in-place)","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> reverse(LP.square())\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[-1.0, -0.0], [-0.0, -1.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To transform a lattice, so that site positions r become f(r) use transform","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> f(r) = SA[0 1; 1 0] * r\nf (generic function with 1 method)\n\njulia> rotated_honeycomb = transform(LP.honeycomb(a0 = √3), f)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 0.866025], [1.5, -0.866025]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> sites(rotated_honeycomb)\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 0.0]\n [0.5, 0.0]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"To translate a lattice by a displacement vector δr use translate","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> δr = SA[0, 1];\n\njulia> sites(translate(rotated_honeycomb, δr))\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 1.0]\n [0.5, 1.0]","category":"page"},{"location":"tutorial/lattices/#Currying:-chaining-transformations-with-the-operator","page":"Lattices","title":"Currying: chaining transformations with the |> operator","text":"","category":"section"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"Many functions in Quantica.jl have a \"curried\" version that allows them to be chained together using the pipe operator |>.","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"note: Definition of currying\nThe curried version of a function f(x1, x2...) is f´ = x1 -> f(x2...), so that the curried form of f(x1, x2...) is x2 |> f´(x2...), or f´(x2...)(x1). This gives the first argument x1 a privileged role. Users of object-oriented languages such as Python may find this use of the |> operator somewhat similar to the way the dot operator works there (i.e. x1.f(x2...)).","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"The last example above can then be written as","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"julia> LP.honeycomb(a0 = √3) |> transform(f) |> translate(δr) |> sites\n2-element Vector{SVector{2, Float64}}:\n [-0.5, 1.0]\n [0.5, 1.0]","category":"page"},{"location":"tutorial/lattices/","page":"Lattices","title":"Lattices","text":"This type of curried syntax is natural in Quantica, and will be used extensively in this tutorial.","category":"page"},{"location":"tutorial/glossary/#Glossary","page":"Glossary","title":"Glossary","text":"","category":"section"},{"location":"tutorial/glossary/","page":"Glossary","title":"Glossary","text":"This is a summary of the type of objects you will be studying.","category":"page"},{"location":"tutorial/glossary/","page":"Glossary","title":"Glossary","text":"Sublat: a sublattice, representing a number of identical sites within the unit cell of a bounded or unbounded lattice. Each site has a position in an E-dimensional space (E is called the embedding dimension). All sites in a given Sublat will be able to hold the same number of orbitals, and they can be thought of as identical atoms. Each Sublat in a Lattice can be given a unique name, by default :A, :B, etc.\nLattice: a collection of Sublats plus a collection of L Bravais vectors that define the periodicity of the lattice. A bounded lattice has L=0, and no Bravais vectors. A Lattice with L > 0 can be understood as a periodic (unbounded) collection of unit cells, each containing a set of sites, each of which belongs to a different sublattice.\nSiteSelector: a rule that defines a subset of sites in a Lattice (not necessarily restricted to a single unit cell)\nHopSelector: a rule that defines a subset of site pairs in a Lattice (not necessarily restricted to the same unit cell)\nLatticeSlice: a finite subset of sites in a Lattice, defined by their cell index (an L-dimensional integer vector, usually denoted by n or cell) and their site index within the unit cell (an integer). A LatticeSlice an be constructed by combining a Lattice and a (bounded) SiteSelector.\nAbstractModel: either a TightBindingModel or a ParametricModel\nTightBindingModel: a set of HoppingTerms and OnsiteTerms\nOnsiteTerm: a rule that, applied to a single site, produces a scalar or a (square) matrix that represents the intra-site Hamiltonian elements (single or multi-orbital)\nHoppingTerm: a rule that, applied to a pair of sites, produces a scalar or a matrix that represents the inter-site Hamiltonian elements (single or multi-orbital)\nParametricModel: a set of ParametricOnsiteTerms and ParametricHoppingTerms\nParametricOnsiteTerm: an OnsiteTerm that depends on a set of free parameters that can be adjusted, and that may or may not have a default value\nParametricHoppingTerm: a HoppingTerm that depends on parameters, like ParametricOnsiteTerm above\nAbstractHamiltonian: either a Hamiltonian or a ParametricHamiltonian\nHamiltonian: a Lattice combined with a TightBindingModel.\nIt also includes a specification of the number of orbitals in each Sublat in the Lattice. A Hamiltonian represents a tight-binding Hamiltonian sharing the same periodicity as the Lattice (it is translationally invariant under Bravais vector shifts).\nParametricHamiltonian: like the above, but using a ParametricModel, which makes it dependent on a set of free parameters that can be efficiently adjusted.\nAn h::AbstractHamiltonian can be used to produce a Bloch matrix h(ϕ; params...) of the same size as the number of orbitals per unit cell, where ϕ = [ϕᵢ...] are Bloch phases and params are values for the free parameters, if any.\nSpectrum: the set of eigenpairs (eigenvalues and corresponding eigenvectors) of a Bloch matrix. It can be computed with a number of EigenSolvers.\nBandstructure: a collection of spectra, evaluated over a discrete mesh (typically a discretization of the Brillouin zone), that is connected to its mesh neighbors into a linearly-interpolated approximation of the AbstractHamiltonian's bandstructure.\nSelfEnergy: an operator Σ(ω) defined to act on a LatticeSlice of an AbstractHamiltonian that depends on energy ω.\nOpenHamiltonian: an AbstractHamiltonian combined with a set of SelfEnergies\nGreenFunction: an OpenHamiltonian combined with an AbstractGreenSolver, which is an algorithm that can in general compute the retarded or advanced Green function at any energy between any subset of sites of the underlying lattice.\nGreenSlice: a GreenFunction evaluated on a specific set of sites, but at an unspecified energy\nGreenSolution: a GreenFunction evaluated at a specific energy, but on an unspecified set of sites\nOrbitalSliceArray: an AbstractArray that can be indexed with a SiteSelector, in addition to the usual scalar indexing. Particular cases are OrbitalSliceMatrix and OrbitalSliceVector. This is the most common type obtained from GreenFunctions and observables obtained from them.\nObservables: Supported observables, obtained from Green functions using various algorithms, include local density of states, density matrices, current densities, transmission probabilities, conductance and Josephson currents","category":"page"},{"location":"advanced/wannier90/#Wannier90-imports","page":"Wannier90 imports","title":"Wannier90 imports","text":"","category":"section"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"A common way to obtain quantitative tight-binding models of materials is to Wannierize density-functional-theory (DFT) bandstructures. In a nutshell, this procedure consists in obtaining a basis set of a subspace of some DFT bandstructure, subject to the condition that the obtained states are maximally localized. A popular implementation of this algorithm is (Wannier90)[https://wannier.org]. Among other things, this tool produces output files that encode a tight-binding Hamiltonian for the material and the matrix elements of the position operator in the maximally localized Wannier basis.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Quantica.jl includes a function that can import Wannier90 tight-binding files. By default these files are 3D systems","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = ExternalPresets.wannier90(\"wannier_tb.dat\")\nWannierBuilder{Float64,3} : 3-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 755\n elements : 36388\n modifiers : 0","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"In this case, however, the model in the \"wannier_tb.dat\" file is a 2D MoS2 crystal. We can project out all out-of-plane matrix elements by specifying the dimension with dim. We can also drop any Hamiltonian matrix element smaller than, say htol = 1e-5, and any position matrix element of norm smaller than rtol = 1e-4. This greatly simplifies the problem","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = ExternalPresets.wannier90(\"wannier_tb.dat\"; dim = 2, htol = 1e-5, rtol = 1e-4)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7510\n modifiers : 0","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"This object can then be converted into a Hamiltonian h or a position operator r","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> h = hamiltonian(w)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 10\n Hoppings : 7500\n Coordination : 750.0\n\njulia> r = position(w)\nBarebonesOperator{2}: a simple collection of 2D Bloch harmonics\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Element type : SVector{2, ComplexF64}\n Nonzero elements : 7408","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Note that r is not of type Hamiltonian. The BarebonesOperator is a specially simple operator type that simply encodes a number of Bloch harmonics (matrices between different unit cells) of arbitrary element type. It supports only a subset of the funcitionality of AbstractHamiltonians. In particular, it supports indexing:","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> r[SA[0,0]]\n10×10 SparseArrays.SparseMatrixCSC{SVector{2, ComplexF64}, Int64} with 50 stored entries:\n [-0.000563148+0.0im, 1.79768+0.0im] … ⋅\n ⋅ [0.164126-2.15538e-5im, -0.000484848-0.0144407im]\n ⋅ [0.0195449-4.9251e-5im, 2.02798e-7+0.00140866im]\n [2.48859e-5-0.0185437im, -0.00534254-1.88085e-5im] ⋅\n ⋅ [2.07772e-7-0.00769914im, 0.00831306+1.45056e-5im]\n [-0.00340134-1.02057e-5im, 1.89607e-5+0.00656423im] … ⋅\n [-0.000371236+0.0227337im, -0.101768+1.64659e-5im] ⋅\n ⋅ [0.210672-5.77589e-5im, -0.000233323-0.00456068im]\n [0.164126-2.14909e-5im, -0.000483435-0.0144407im] ⋅\n ⋅ [0.000608652+0.0im, 2.12317+0.0im]\n\njulia> r[sites(1), sites(4)]\n2-element SVector{2, ComplexF64} with indices SOneTo(2):\n 2.4885857e-5 + 0.018543702im\n -0.0053425408 + 1.8808481e-5im","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"It is possible to modify the imported Wannier90 models using the full Quantica.jl machinery. For example, we can add any AbstractModel to the Wannier90 model upon import just by passing it as a second argument","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w = EP.wannier90(\"wannier_tb.dat\", @onsite((; Δ = 0) -> Δ); dim = 2)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7560\n modifiers : 1\n\njulia> h = hamiltonian(w)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 10\n Hoppings : 7540\n Coordination : 754.0\n Parameters : [:Δ]","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"Note that since we used a ParametricModel with a single parametric term, this introduced one modifier, since ParametricModels are simply an ordinary base model plus one modifier for each parametric term. As a result, h is now parametric.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"note: Adding models after import\nAlthough the above is the recommended way to add a Quantica model to a Wannier90 model (i.e. explicitly at import time), one can also do the same with Quantica.add!(EP.hbuilder(w), model) to modify w in place after its creation. This employs internal functionality, so it is not recommended, as it could change without warning.","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"We can also use the following syntax apply one or more modifiers explicitly","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> w´ = w |> @onsite!((o; k = 0) -> o + k)\nWannierBuilder{Float64,2} : 2-dimensional Hamiltonian builder of type Float64 from Wannier90 input\n cells : 151\n elements : 7560\n modifiers : 2","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"An interesting application of modifiers is the addition of an electric field that couples to the full r operator. In an strict tight-binding limit, we would add an electric field E simply as an onsite potential","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> hE = h |> @onsite!((o, r; E = SA[0,0]) -> o + E'*r);","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"However, we actually have the full r operator now, which includes non-diagonal matrix elements. We can then incorporate the electric field term E'*r more precisely. We can do so using the --> syntax and the indexing functionality of the r::BarebonesOperator that we obtained from Wannier90","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"julia> hE = h |> @onsite!((o, i; E = SA[0,0]) --> o + E'*r[i,i]) |> @hopping!((t, i, j; E = SA[0,0]) --> t + E'*r[i,j]);","category":"page"},{"location":"advanced/wannier90/","page":"Wannier90 imports","title":"Wannier90 imports","text":"note: Closures over non-constant objects\nNote that the above creates a closure over r, which is not const. As a result this would incur a small performance and allocation cost when evaluating hE(E=...). We can avoid it e.g. by defining r as a constant, const r = sites(w).","category":"page"},{"location":"tutorial/hamiltonians/#Hamiltonians","page":"Hamiltonians","title":"Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We build a Hamiltonian by combining a Lattice and a TightbindingModel, optionally specifying also the number of orbitals on each sublattice if there is more than one. A spinful graphene model (two orbitals per site in both sublattices) with nearest neighbor hopping t0 = 2.7 would be written as","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> lat = LP.honeycomb(); model = hopping(2.7*I);\n\njulia> h = hamiltonian(lat, model; orbitals = 2)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"A crucial thing to remember when defining multi-orbital Hamiltonians as the above is that onsite and hopping amplitudes need to be matrices of the correct size. The symbol I in Julia represents the identity matrix of any size, which is convenient to define a spin-preserving hopping in the case above. An alternative would be to use model = hopping(2.7*SA[1 0; 0 1]).","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Models with different number of orbitals per sublattice\nNon-homogeneous multiorbital models are more advanced but are fully supported in Quantica.jl. Just use orbitals = (n₁, n₂,...) to have nᵢ orbitals in sublattice i, and make sure your model is consistent with that. As in the case of the dim keyword in lattice, you can also use Val(nᵢ) for marginally faster construction.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Similarly to LatticePresets, we also have HamiltonianPresets, also aliased as HP. Currently, we have only HP.graphene(...) and HP.twisted_bilayer_graphene(...), but we expect to extend this library in the future (see the docstring of HP).","category":"page"},{"location":"tutorial/hamiltonians/#A-more-elaborate-example:-the-Kane-Mele-model","page":"Hamiltonians","title":"A more elaborate example: the Kane-Mele model","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The Kane-Mele model for graphene describes intrinsic spin-orbit coupling (SOC), in the form of an imaginary second-nearest-neighbor hopping between same-sublattice sites, with a sign that alternates depending on hop direction dr. A possible implementation in Quantica.jl would be","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"SOC(dr) = 0.05 * ifelse(iseven(round(Int, atan(dr[2], dr[1])/(pi/3))), im, -im)\n\nmodel =\n hopping(1, range = neighbors(1)) +\n hopping((r, dr) -> SOC(dr); sublats = :A => :A, range = neighbors(2)) +\n hopping((r, dr) -> -SOC(dr); sublats = :B => :B, range = neighbors(2))\n\nh = LatticePresets.honeycomb() |> model\n\nqplot(h)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"\"Kane-Mele","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Interactive tooltips in the visualization of h are enabled by default (use keyword inspector = false to disable them). They allows to navigate each onsite and hopping amplitude graphically. Note that sites connected to the unit cell of h by some hopping are included, but are rendered with partial transparency by default.","category":"page"},{"location":"tutorial/hamiltonians/#ParametricHamiltonians","page":"Hamiltonians","title":"ParametricHamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"If we use a ParametricModel instead of a simple TightBindingModel we will obtain a ParametricHamiltonian instead of a simple Hamiltonian, both of which are subtypes of the AbstractHamiltonian type","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> model_param = @hopping((; t = 2.7) -> t*I);\n\njulia> h_param = hamiltonian(lat, model_param; orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:t]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can also apply Modifiers by passing them as extra arguments to hamiltonian, which results again in a ParametricHamiltonian with the parametric modifiers applied","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> peierls! = @hopping!((t, r, dr; Bz = 0) -> t * cis(-Bz/2 * SA[-r[2], r[1]]' * dr));\n\njulia> h_param_mod = hamiltonian(lat, model_param, peierls!; orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:Bz, :t]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that SA[-r[2], r[1]] above is a 2D SVector, because since the embedding dimension is E = 2, both r and dr are also 2D SVectors.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can also apply modifiers to an already constructed AbstractHamiltonian. The following is equivalent to the above","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param_mod = hamiltonian(h_param, peierls!);","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Modifiers do not commute\nWe can add as many modifiers as we need by passing them as extra arguments to hamiltonian, and they will be applied sequentially, one by one. Beware, however, that modifiers do not necessarily commute, in the sense that the result will in general depend on their order.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We can obtain a plain Hamiltonian from a ParametricHamiltonian by applying specific values to its parameters. To do so, simply use the call syntax with parameters as keyword arguments","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param_mod(Bz = 0.1, t = 1)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Syntax `lat |> model` and `h |> modifier\nThe common cases lat |> hamiltonian(model) (or hamiltonian(lat, model)) and h |> hamiltonian(modifier) (or hamiltonian(h, modifier)) can be also written as lat |> model and h |> modifier, respectively. Hence hamiltonian(lat, model, modifier) may be written as lat |> model |> modifier. This form however does not allow to specify the number of orbitals per sublattice (it will be one, the default).","category":"page"},{"location":"tutorial/hamiltonians/#Obtaining-actual-matrices","page":"Hamiltonians","title":"Obtaining actual matrices","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"For an L-dimensional h::AbstractHamiltonian (i.e. defined on a Lattice with L Bravais vectors), the Hamiltonian matrix between any unit cell with cell index n and another unit cell at n+dn (here known as a Hamiltonian \"harmonic\") is given by h[dn]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h[(1,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n ⋅ ⋅ 2.7+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.7+0.0im\n ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅\n\njulia> h[(0,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 2.7+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.7+0.0im\n 2.7+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 2.7+0.0im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"tip: Cell distance indices\nWe can use Tuples or SVectors for cell distance indices dn. An empty Tuple dn = () will always return the main intra-unitcell harmonic: h[()] = h[(0,0...)] = h[SA[0,0...]].","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"note: Bounded Hamiltonians\nIf the Hamiltonian has a bounded lattice (i.e. it has L=0 Bravais vectors), we will simply use an empty tuple to obtain its matrix h[()]. This is not in conflict with the above syntax.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that if h is a ParametricHamiltonian, such as h_param above, we will get zeros in place of the unspecified parametric terms, unless we actually first specify the values of the parameters","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h_param[(0,0)] # Parameter t is not specified -> it is not applied\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 0.0+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 0.0+0.0im ⋅ ⋅\n\njulia> h_param(t=2)[(0,0)]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 2.0+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 2.0+0.0im\n 2.0+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 2.0+0.0im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"note: ParametricHamiltonian harmonics\nThe above behavior for unspecified parameters is not set in stone and may change in future versions. Another option would be to apply their default values (which may, however, not exist).","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We are usually not interested in the harmonics h[dn] themselves, but rather in the Bloch matrix of a Hamiltonian","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"H(phi) = sum_dn H_dn exp(-i phi * dn)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"where H_dn are the Hamiltonian harmonics, phi = (phi_1 phi_2) = (kcdot A_1 kcdot A_2) are the Bloch phases, k is the Bloch wavevector and A_i are the Bravais vectors.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"We obtain the Bloch matrix using the syntax h(ϕ; params...)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h((0,0))\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 8.1+0.0im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 8.1+0.0im\n 8.1+0.0im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 8.1+0.0im ⋅ ⋅\n\njulia> h_param_mod((0.2, 0.3); B = 0.1)\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 7.92559-1.33431im 0.0+0.0im\n ⋅ ⋅ 0.0+0.0im 7.92559-1.33431im\n 7.92559+1.33431im 0.0+0.0im ⋅ ⋅\n 0.0+0.0im 7.92559+1.33431im ⋅ ⋅","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Note that unspecified parameters take their default values when using the call syntax (as per the standard Julia convention). Any unspecified parameter that does not have a default value will produce an UndefKeywordError error.","category":"page"},{"location":"tutorial/hamiltonians/#Transforming-Hamiltonians","page":"Hamiltonians","title":"Transforming Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Like with lattices, we can transform an h::AbstractHamiltonians using supercell, reverse, transform and translate. All these except supercell operate only on the underlying lattice(h) of h, leaving the hoppings and onsite elements unchanged. Meanwhile, supercell acts on lattice(h) but also copies the hoppings and onsites of h onto the new sites, preserving the periodicity of the original h.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Additionally, we can also use torus, which makes the h lattice periodic along some (or all) of its Bravais vectors, while leaving the rest unbounded.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> torus(HP.graphene(), (0, :))\nHamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 4\n Coordination : 2.0","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The phases argument of torus(h, phases) is a Tuple of real numbers and/or colons (:), of length equal to the lattice dimension of h. Each real number ϕᵢ corresponds to a Bravais vector along which the transformed lattice will become periodic, picking up a phase exp(iϕᵢ) in the new hoppings, while each colon leaves the lattice unbounded along the corresponding Bravais vector. In a way torus is dual to supercell, in that it applies a different boundary condition to the lattice along the eliminated Bravais vectors, periodic instead of open, as in the case of supercell. The phases ϕᵢ are also connected to Bloch phases, in the sense that e.g. torus(h, (ϕ₁, :))(ϕ₂) == h(ϕ₁, ϕ₂)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Caveat of the Bloch-torus duality\nThe relation torus(h, phases)(()) = h(phases) is quite general. However, in some cases with position-dependent models, this may not hold. This may happen when some of the new hoppings added by torus are already present in h, as in cases with hoppings at ranges equal or larger than half the size of the unit cell.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"It's important to understand that, when transforming an h::AbstractHamiltonian, the model used to build h is not re-evaluated. Hoppings and onsite energies are merely copied so as to preserve the periodicity of the original h. As a consequence, these two constructions give different Hamiltonians","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1 = LP.linear() |> supercell(4) |> hamiltonian(onsite(r -> r[1]));\n\njulia> h2 = LP.linear() |> hamiltonian(onsite(r -> r[1])) |> supercell(4);","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"In the case of h1 the onsite model is applied to the 4-site unitcell. Since each site has a different position, each gets a different onsite energy.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im ⋅ ⋅ ⋅\n ⋅ 1.0+0.0im ⋅ ⋅\n ⋅ ⋅ 2.0+0.0im ⋅\n ⋅ ⋅ ⋅ 3.0+0.0im","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"In contrast h2 first gets the onsite model applied with a 1-site unitcell at position r = SA[0], so all sites in the lattice get onsite energy zero. Only then it is expanded with supercell, which generates a 4-site unitcell with zero onsite energy on all its sites","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h2[()]\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im ⋅ ⋅ ⋅\n ⋅ 0.0+0.0im ⋅ ⋅\n ⋅ ⋅ 0.0+0.0im ⋅\n ⋅ ⋅ ⋅ 0.0+0.0im","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"As a consequence, h and supercell(h) represent exactly the same system, with the same observables, but with a different choice of unitcell.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"These two different behaviors make sense in different situations, so it is important to be aware of the order dependence of transformations. Similar considerations apply to transform, translate and torus when models are position dependent.","category":"page"},{"location":"tutorial/hamiltonians/#Combining-Hamiltonians","page":"Hamiltonians","title":"Combining Hamiltonians","text":"","category":"section"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"Multiple h::AbstractHamiltonians (or multiple l::Lattices) can be combined into one with combine.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> h1 = LP.linear(dim = 2) |> hopping(1); h2 = LP.linear(dim = 2, names = :B) |> hopping(1) |> translate(SA[0,1]) |> @onsite!((o; p=1) -> o+p);\n\njulia> combine(h1, h2; coupling = hopping(2))\nParametricHamiltonian{Float64,2,1}: Parametric Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n Parameters : [:p]","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The coupling keyword, available when combining h::AbstractHamiltonians, is a hopping model that is applied between each h. It can be constrained as usual with hopselectors and also be parametric. If either coupling or any of the combined h is parametric, the result of combine will be a ParametricHamiltonian, or a Hamiltonian otherwise.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The objects to be combined must satisfy some conditions:","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"They must have the same Bravais vectors (modulo reorderings), which will be then inherited by the combined object.\nThey must have the same position type (the T in AbstractHamiltonian{T} and Lattice{T})\nThey must have no repeated sublattice names among them (unless the combined object is non-parametric)","category":"page"},{"location":"tutorial/tutorial/#Tutorial","page":"Welcome","title":"Tutorial","text":"","category":"section"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Welcome to the Quantica.jl tutorial!","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Here you will learn how to use Quantica.jl to build and compute properties of tight-binding models. This includes","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Defining general Lattices in arbitrary dimensions\nDefining generic tight-binding Models with arbitrary parameter dependences\nBuilding Hamiltonians of mono- or multiorbital systems by combining Lattices and Models\nComputing Bandstructures of Hamiltonians\nComputing GreenFunctions of Hamiltonians or OpenHamiltonians (i.e. Hamiltonians with attached self-energies from other Hamiltonians, such as leads).\nComputing Observables from Green functions, such as spectral densities, current densities, local and nonlocal conductances, Josephson currents, critical currents, transmission probabilities, etc.","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"Check the menu on the left for shortcuts to the relevant sections.","category":"page"},{"location":"tutorial/tutorial/","page":"Welcome","title":"Welcome","text":"tip: Check the docstrings\nFull usage instructions on all Quantica.jl functions can be found here or within the Julia REPL by querying their docstrings. For example, to obtain details on the hamiltonian function or on the available LatticePresets, just type ?hamiltonian or ?LatticePresets.","category":"page"},{"location":"advanced/serializers/#Serializers","page":"Serializers","title":"Serializers","text":"","category":"section"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"Serializers are useful to translate between a complex data structure and a stream of plain numbers of a given type. Serialization and deserialization is a common encode/decode operation in programming language.","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"In Quantica, a s::Serializer{T} is an object that takes an h::AbstractHamiltonian, a selection of the sites and hoppings to be translated, and an encoder/decoder pair of functions to translate each element into a portion of the stream. This s can then be used to convert the specified elements of h into a vector of scalars of type T and back, possibly after applying some parameter values. Consider this example from the serializer docstring","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"julia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);\n\njulia> as = serializer(Float64, h1; encoder = s -> reim(s), decoder = v -> complex(v[1], v[2]))\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : ParametricHamiltonian\n Object parameters : [:U]\n Stream parameter : :stream\n Output eltype : Float64\n Encoder/Decoder : Single\n Length : 6\n\njulia> v = serialize(as; U = 4)\n6-element Vector{Float64}:\n -4.0\n 0.0\n -0.0\n -1.0\n 0.0\n 1.0\n\njulia> h2 = deserialize!(as, v);\n\njulia> h2 == h1(U = 4)\ntrue\n\njulia> h3 = hamiltonian(as)\nParametricHamiltonian{Float64,1,1}: Parametric Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 1 × 1\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 1\n Hoppings : 2\n Coordination : 2.0\n Parameters : [:U, :stream]\n\njulia> h3(stream = v, U = 5) == h1(U = 4) # stream overwrites the U=5 onsite terms\ntrue","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"The serializer functionality is designed with efficiency in mind. Using the in-place serialize!/deserialize! pair we can do the encode/decode round trip without allocations","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"julia> using BenchmarkTools\n\njulia> v = Vector{Float64}(undef, length(as));\n\njulia> deserialize!(as, serialize!(v, as)) === Quantica.call!(h1, U = 4)\ntrue\n\njulia> @btime deserialize!($as, serialize!($v, $as));\n 149.737 ns (0 allocations: 0 bytes)","category":"page"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"It also allows powerful compression into relevant degrees of freedom through appropriate use of encoders/decoders, see the serializer docstring.","category":"page"},{"location":"advanced/serializers/#Serializers-of-OrbitalSliceArrays","page":"Serializers","title":"Serializers of OrbitalSliceArrays","text":"","category":"section"},{"location":"advanced/serializers/","page":"Serializers","title":"Serializers","text":"Serialization of OrbitalSliceArrays is simpler than for AbstractHamiltonians, as there is no need for an intermediate Serializer object. To serialize an m::OrbitalSliceArray simply do v = serialize(m). To deserialize, just do m´ = deserialize(m, v).","category":"page"},{"location":"api/#api","page":"API","title":"API","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"CurrentModule = Quantica","category":"page"},{"location":"api/","page":"API","title":"API","text":"","category":"page"},{"location":"api/","page":"API","title":"API","text":"Modules = [Quantica]","category":"page"},{"location":"api/#Quantica.EigenSolvers","page":"API","title":"Quantica.EigenSolvers","text":"EigenSolvers is a Quantica submodule containing support for several pre-defined eigensolver extensions. The alias ES can be used in place of EigenSolvers. Currently supported solvers are\n\nES.LinearAlgebra(; kw...) # Uses `eigen(mat; kw...)` from the `LinearAlgebra` package\nES.Arpack(; kw...) # Uses `eigs(mat; kw...)` from the `Arpack` package (WARNING: Arpack is not thread-safe)\nES.KrylovKit(params...; kw...) # Uses `eigsolve(mat, params...; kw...)` from the `KrylovKit` package\nES.ArnoldiMethod(; kw...) # Uses `partialschur(mat; kw...)` from the `ArnoldiMethod` package.\n\nTo use each of these solvers the corresponding package must be loaded with e.g. using ArnoldiMethod. The exception is the default ES.LinearAlgebra which is a direct Quantica dependency and does not require loading.\n\nAdditionally, to compute interior eigenvalues, we can use a shift-invert method around energy ϵ0 (uses LinearMaps and a LinearAlgebra.lu factorization), combined with any solver s from the list above:\n\nES.ShiftInvert(s, ϵ0) # Perform a lu-based shift-invert with solver `s`\n\nThe ShiftInvert solver extension requires doing using LinearMaps.\n\nExamples\n\njulia> using LinearMaps, ArnoldiMethod # loads required extensions\n\njulia> h = HP.graphene(t0 = 1) |> supercell(10);\n\njulia> spectrum(h, (0,0); solver = ES.ShiftInvert(ES.ArnoldiMethod(nev = 4), 0.0)) |> energies\n4-element Vector{ComplexF64}:\n -0.3819660112501042 + 2.407681231060336e-16im\n -0.6180339887498942 - 2.7336317916863215e-16im\n 0.6180339887498937 - 1.7243387890744497e-16im\n 0.3819660112501042 - 1.083582785131051e-16im\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.ExternalPresets","page":"API","title":"Quantica.ExternalPresets","text":"ExternalPresets is a Quantica submodule containing utilities to import objects from external applications The alias EP can be used in place of ExternalPresets. Currently supported importers are\n\nEP.wannier90(args...; kw...)\n\nFor details on the arguments args and keyword arguments kw see the docstring for the corresponding function.\n\nSee also\n\n`LatticePresets`, `RegionPresets`, `HamiltonianPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.GreenSolvers","page":"API","title":"Quantica.GreenSolvers","text":"GreenSolvers is a Quantica submodule containing several pre-defined Green function solvers. The alias GS can be used in place of GS. Currently supported solvers and their possible keyword arguments are\n\nGS.SparseLU() : Direct inversion solver for 0D Hamiltonians using a SparseArrays.lu(hmat) factorization\nGS.Spectrum(; spectrum_kw...) : Diagonalization solver for 0D Hamiltonians using spectrum(h; spectrum_kw...)\nspectrum_kw... : keyword arguments passed on to spectrum\nThis solver does not accept ParametricHamiltonians. Convert to Hamiltonian with h(; params...) first. Contact self-energies that depend on parameters are supported.\nGS.Schur(; boundary = Inf) : Solver for 1D Hamiltonians based on a deflated, generalized Schur factorization\nboundary : 1D cell index of a boundary cell, or Inf for no boundaries. Equivalent to removing that specific cell from the lattice when computing the Green function.\nGS.KPM(; order = 100, bandrange = missing, kernel = I) : Kernel polynomial method solver for 0D Hamiltonians\norder : order of the expansion in Chebyshev polynomials Tₙ(h) of the Hamiltonian h (lowest possible order is n = 0).\nbandrange : a (min_energy, max_energy)::Tuple interval that encompasses the full band of the Hamiltonian. If missing, it is computed automatically, but using ArnoldiMethod is required first.\nkernel : generalization that computes momenta as μₙ = Tr[Tₙ(h)*kernel], so that the local density of states (see ldos) becomes the density of the kernel operator.\nThis solver does not allow arbitrary indexing of the resulting g::GreenFunction, only on contacts g[contact_ind::Integer]. If the system has none, we can add a dummy contact using attach(h, nothing; sites...), see attach.\nGS.Bands(bands_arguments; boundary = missing, bands_kw...): solver based on the integration of bandstructure simplices\nbands_arguments: positional arguments passed on to bands\nbands_kw: keyword arguments passed on to bands\nboundary: either missing (no boundary), or dir => cell_pos (single boundary), where dir::Integer is the Bravais vector normal to the boundary, and cell_pos::Integer the value of cell indices cells[dir] that define the boundary (i.e. cells[dir] <= cell_pos are vaccum)\nThis solver only allows zero or one boundary. WARNING: if a boundary is used, the algorithm may become unstable for very fine band meshes.\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.HamiltonianPresets","page":"API","title":"Quantica.HamiltonianPresets","text":"HamiltonianPresets is a Quantica submodule containing several pre-defined Hamiltonians. The alias HP can be used in place of HamiltonianPresets. Currently supported hamiltonians are\n\nHP.graphene(; kw...)\nHP.twisted_bilayer_graphene(; kw...)\n\nFor details on the keyword arguments kw see the corresponding docstring\n\njulia> HamiltonianPresets.twisted_bilayer_graphene(twistindices = (30, 1))\nHamiltonian{Float64,3,2}: Hamiltonian on a 2D Lattice in 3D space\n Bloch harmonics : 7\n Harmonic size : 11164 × 11164\n Orbitals : [1, 1, 1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 315684\n Coordination : 28.27696\n\nSee also\n\n`LatticePresets`, `RegionPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.LatticePresets","page":"API","title":"Quantica.LatticePresets","text":"LatticePresets is a Quantica submodule containing several pre-defined lattices. The alias LP can be used in place of LatticePresets. Currently supported lattices are\n\nLP.linear(; a0 = 1, kw...) # linear lattice in 1D\nLP.square(; a0 = 1, kw...) # square lattice in 2D\nLP.triangular(; a0 = 1, kw...) # triangular lattice in 2D\nLP.honeycomb(; a0 = 1, kw...) # honeycomb lattice in 2D\nLP.cubic(; a0 = 1, kw...) # cubic lattice in 3D\nLP.fcc(; a0 = 1, kw...) # face-centered-cubic lattice in 3D\nLP.bcc(; a0 = 1, kw...) # body-centered-cubic lattice in 3D\nLP.hcp(; a0 = 1, kw...) # hexagonal-closed-packed lattice in 3D\n\nIn all cases a0 denotes the lattice constant, and kw... are extra keywords forwarded to lattice.\n\nExamples\n\njulia> LatticePresets.honeycomb(names = (:C, :D))\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[0.5, 0.866025], [-0.5, 0.866025]]\n Sublattices : 2\n Names : (:C, :D)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> LatticePresets.cubic(bravais = ((1, 0), (0, 2)))\nLattice{Float64,3,2} : 2D lattice in 3D space\n Bravais vectors : [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell\n\nSee also\n\n`RegionPresets`, `HamiltonianPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.Paths","page":"API","title":"Quantica.Paths","text":"Paths\n\nA Quantica submodule that contains representations of different integration paths in the complex-ω plane for integrals of the form ∫f(ω)g(ω)dω, where f(ω) is the Fermi distribution at chemical potential µ and temperature kBT. Available paths are:\n\nPaths.radial(ωscale::Real, ϕ)\n\nA four-segment path from ω = -Inf to ω = Inf. The path first ascends along an arc of angle ϕ (with 0 <= ϕ < π/2) and infinite radius. It then converges along a straight line in the second ω-µ quadrant to the chemical potential origin ω = µ. Finally it performs the mirror-symmetric itinerary in the first ω-µ quadrant, ending on the real axis at ω = Inf. The radial segments are traversed at a rate dictated by ωscale, that should represent some relevant energy scale in the system for optimal convergence of integrals. At zero temperature kBT = 0, the two last segments don't contribute and are elided.\n\nPaths.sawtooth(ωpoints...; slope = 1, imshift = true)\n\nA path connecting all points in the ωpoints collection (should all be real), but departing between each two into the complex plane and back with the given slope, forming a sawtooth path. Note that an extra point µ is added to the collection, where µ is the chemical potential, and the real(ω)>µ segments are elided at zero temperatures. If imshift = true all ωpoints (of type T<:Real) are shifted by sqrt(eps(T)) to avoid the real axis.\n\nPaths.sawtooth(ωmax::Real; kw...)\n\nAs above with ωpoints = (-ωmax, ωmax).\n\nPaths.polygon(ωpoints...)\n\nA general polygonal path connecting ωpoints, which can be any collection of real or complex numbers\n\nPaths.polygon(ωfunc::Function)\n\nA ageneral polygonal path connecting ωpoints = ωfunc(µ, kBT; params...). This is useful when the desired integration path depends on the chemical potential µ, temperature kBT or other system parameters params.\n\nSee also\n\n`densitymatrix`, `josephson`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.RegionPresets","page":"API","title":"Quantica.RegionPresets","text":"RegionPresets is a Quantica submodule containing several pre-defined regions of type Region{E}, where E is the space dimension. The alias RP can be used in place of RegionPresets. Supported regions are\n\nRP.circle(radius = 10, center = (0, 0)) # 2D\nRP.ellipse((rx, ry) = (10, 15), center = (0, 0)) # 2D\nRP.square(side = 10, center = (0, 0)) # 2D\nRP.rectangle((sx, sy) = (10, 15), center = (0, 0)) # 2D\nRP.sphere(radius = 10, center = (0, 0, 0)) # 3D\nRP.spheroid((rx, ry, rz) = (10, 15, 20), center = (0, 0, 0)) # 3D\nRP.cube(side = 10, center = (0, 0, 0)) # 3D\nRP.cuboid((sx, sy, sz) = (10, 15, 20), center = (0, 0, 0)) # 3D\n\nCalling a f::Region{E} object on a r::Tuple or r::SVector with f(r) or f(r...) returns true or false if r is inside the region or not. Note that only the first E coordinates of r will be checked. Arbitrary boolean functions can also be wrapped in Region{E} to create custom regions, e.g. f = Region{2}(r -> r[1]^2 < r[2]).\n\nBoolean combinations of Regions are supported using &, |, xor and ! operators, such as annulus = RP.circle(10) & !RP.circle(5).\n\nExamples\n\njulia> RegionPresets.circle(10)(20, 0, 0)\nfalse\n\njulia> RegionPresets.circle(10)(0, 0, 20)\ntrue\n\nSee also\n\n`LatticePresets`, `HamiltonianPresets`, `ExternalPresets`\n\n\n\n\n\n","category":"module"},{"location":"api/#Quantica.zerofield","page":"API","title":"Quantica.zerofield","text":" zerofield\n\nAn sigleton of type ZeroField that represents a zero-valued field. It has the property that it returns zero no matter how it is indexed (zerofield[inds...] = 0.0 * I), so it is useful as a default value in a non-spatial model involving mean fields. See meanfield for a usage example.\n\nSee also\n\n`meanfield`\n\n\n\n\n\n","category":"constant"},{"location":"api/#Quantica.BoxIterator","page":"API","title":"Quantica.BoxIterator","text":"BoxIterator(seed::SVector{N,Int}; maxiterations = TOOMANYITERS)\n\nCartesian iterator iter over SVector{N,Int}s (cells) that starts at seed and grows outwards in the form of a box of increasing sides (not necesarily equal) until it encompasses a certain N-dimensional region. To signal that a cell is in the desired region the user calls acceptcell!(iter, cell).\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceArray","page":"API","title":"Quantica.OrbitalSliceArray","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceMatrix","page":"API","title":"Quantica.OrbitalSliceMatrix","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Quantica.OrbitalSliceVector","page":"API","title":"Quantica.OrbitalSliceVector","text":"OrbitalSliceArray <: AbstractArray\n\nA type of AbstractArray defined over a set of orbitals (see also orbaxes). It wraps a regular array that can be obtained with parent(::OrbitalSliceArray), and supports all the general AbstractArray interface. In addition, it also supports indexing using siteselectors and cellindices. OrbitalSliceVector and OrbitalSliceMatrix are special cases of OrbitalSliceArray of dimension 1 and 2 respectively.\n\nThis is the common output type produced by GreenFunctions and most observables.\n\nNote that for m::OrbitalSliceMatrix, mat[i] is equivalent to mat[i,i], and mat[; sel...] is equivalent to mat[(; sel...), (; sel...)].\n\nsiteselector indexing\n\nmat[(; rowsites...), (; colsites...)]\nmat[rowsel::SiteSelector, colsel::SiteSelector]\n\nIf we index an OrbitalSliceMatrix with s::NamedTuple or a siteselector(; s...), we obtain a new OrbitalSliceMatrix over the orbitals of the selected sites.\n\nsites indexing\n\nmat[sites(cell_index, site_indices)]\nmat[sites(row_cell_index, row_site_indices), sites(col_cell_index, col_site_indices)]\n\nIf we index an OrbitalSliceMatrix with sites, we obtain an unwrapped Matrix over the sites with site_indices within cell with cell_index. Here site_indices can be an Int, a container of Int, or a : (for all sites in the unit cell). If any of the specified sites are not already in orbaxes(mat), indexing will throw an error.\n\nNote that in this case we do not obtain a new OrbitalSliceMatrix. This behavior is required for performance, as re-wrapping in a new OrbitalSliceMatrix requires recomputing and allocating the new orbaxes.\n\nview(mat, rows::CellSites, cols::Cellsites = rows)\n\nLike the above, but returns a view instead of a copy of the indexed orbital matrix.\n\nNote: diagonal indexing is currently not supported by OrbitalSliceArray.\n\nExamples\n\njulia> g = LP.linear() |> hamiltonian(hopping(SA[0 1; 1 0]) + onsite(I), orbitals = 2) |> supercell(4) |> greenfunction;\n\njulia> mat = g(0.2)[region = r -> 2<=r[1]<=4]\n6×6 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n -1.93554e-9-0.545545im 0.0-0.0im 0.0-0.0im -0.5+0.218218im 0.4+0.37097im 0.0+0.0im\n 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0-0.0im 0.0+0.0im 0.4+0.37097im\n 0.0-0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im 0.0+0.0im -0.5+0.218218im\n -0.5+0.218218im 0.0-0.0im 0.0-0.0im -1.93554e-9-0.545545im -0.5+0.218218im 0.0+0.0im\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im -1.93554e-9-0.545545im 0.0-0.0im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im 0.0-0.0im -1.93554e-9-0.545545im\n\njulia> mat[(; cells = SA[1]), (; cells = SA[0])]\n2×4 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.4+0.37097im 0.0+0.0im 0.0+0.0im -0.5+0.218218im\n 0.0+0.0im 0.4+0.37097im -0.5+0.218218im 0.0+0.0im\n\njulia> mat[sites(SA[1], 1)]\n2×2 Matrix{ComplexF64}:\n -1.93554e-9-0.545545im 0.0-0.0im\n 0.0-0.0im -1.93554e-9-0.545545im\n\nSee also\n\n`siteselector`, `cellindices`, `orbaxes`\n\n\n\n\n\n","category":"type"},{"location":"api/#Base.position","page":"API","title":"Base.position","text":"position(b::ExternalPresets.WannierBuilder)\n\nReturns the position operator in the Wannier basis. It is given as a r::BarebonesOperator object, which can be indexed as r[s, s´] to obtain matrix elements ⟨s|R|s´⟩ of the position operator R (a vector). Here s and s´ represent site indices, constructed with sites(cell, inds). To obtain the matrix between cells separated by dn::SVector{L,Int}, do r[dn]. The latter will throw an error if the dn harmonic is not present.\n\nSee also\n\n`current`, `sites`\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.reverse","page":"API","title":"Base.reverse","text":"reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})\n\nBuild a new lattice or hamiltonian with the orientation of all Bravais vectors and harmonics reversed.\n\nSee also\n\n`reverse!`, `transform`\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.reverse!","page":"API","title":"Base.reverse!","text":"reverse!(lat_or_h::Union{Lattice,AbstractHamiltonian})\n\nIn-place version of reverse, inverts all Bravais vectors and harmonics of lat_or_h.\n\nSee also\n\n`reverse`, `transform`\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.ishermitian","page":"API","title":"LinearAlgebra.ishermitian","text":"ishermitian(h::Hamiltonian)\n\nCheck whether h is Hermitian. This is not supported for h::ParametricHamiltonian, as the result can depend of the specific values of its parameters.\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.ExternalPresets.wannier90","page":"API","title":"Quantica.ExternalPresets.wannier90","text":"ExternalPresets.wannier90(filename::String; kw...)\n\nImport a Wannier90 tight-binding file in the form of a w::EP.WannierBuilder object. It can be used to obtain a Hamiltonian with hamiltonian(w), and the matrix of the position operator with sites(w).\n\nExternalPresets.wannier90(filename, model::AbstractModel; kw...)\n\nModify the WannierBuilder after import by adding model to it.\n\npush!(w::EP.WannierBuilder, modifier::AbstractModifier)\nw |> modifier\n\nApplies a modifier to w.\n\nKeywords\n\nhtol: skip matrix elements of the Hamiltonian smaller than this (in absolute value). Default: 1e-8\nrtol: skip non-diagonal matrix elements of the position operator smaller than this (in absolute value). Default: 1e-8\ndim: dimensionality of the embedding space for the Wannier orbitals, dropping trailing dimensions beyond dim if smaller than 3. Default: 3\nlatdim: dimensionality of the lattice, dropping trailing dimensions beyond latdim if smaller than 3. Should be latdim <= dim. Default: dim\ntype: override the real number type of the imported system. Default: Float64\n\nExamples\n\njulia> w = EP.wannier90(\"wannier_tb.dat\", @onsite((; o) -> o); htol = 1e-4, rtol = 1e-4, dim = 2, type = Float32)\nWannierBuilder{Float32,2,2} : 2-dimensional Hamiltonian builder from Wannier90 input, with positions of type Float32 in 2D-dimensional space\n cells : 151\n elements : 6724\n modifiers : 1\n\njulia> h = hamiltonian(w)\nParametricHamiltonian{Float32,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Orbitals : [1]\n Element type : scalar (ComplexF32)\n Onsites : 10\n Hoppings : 6704\n Coordination : 670.4\n Parameters : [:o]\n\njulia> r = position(w)\nBarebonesOperator{2}: a simple collection of 2D Bloch harmonics\n Bloch harmonics : 151\n Harmonic size : 10 × 10\n Element type : SVector{2, ComplexF32}\n Nonzero elements : 7408\n\njulia> r[sites(SA[0,0], 3), sites(SA[1,0],2)]\n2-element SVector{2, ComplexF32} with indices SOneTo(2):\n -0.0016230071f0 - 0.00012927242f0im\n 0.008038711f0 + 0.004102786f0im\n\nSee also\n\n`hamiltonian`, `position`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.attach","page":"API","title":"Quantica.attach","text":"attach(h::AbstractHamiltonian, args..; sites...)\nattach(h::OpenHamiltonian, args...; sites...)\n\nBuild an h´::OpenHamiltonian by attaching (adding) a Σ::SelfEnergy to a finite number of sites in h specified by siteselector(; sites...). This also defines a \"contact\" on said sites that can be referred to (with index i::Integer for the i-th attached contact) when slicing Green functions later. Self-energies are taken into account when building the Green function g(ω) = (ω - h´ - Σ(ω))⁻¹ of the resulting h´, see greenfunction.\n\nSelf-energy forms\n\nThe different forms of args yield different types of self-energies Σ. Currently supported forms are:\n\nattach(h, gs::GreenSlice, coupling::AbstractModel; transform = missing, sites...)\n\nAdds a generic self-energy Σ(ω) = V´⋅gs(ω)⋅V on h's sites, where V and V´ are couplings (given by coupling) between said sites and the LatticeSlice in gs (after applying transform to the latter). Allowed forms of gs include both g[bath_sites...] and g[contactind::Integer] where g is any GreenFunction.\n\nattach(h, model::ParametricModel; sites...)\n\nAdd self-energy Σᵢⱼ(ω) defined by a model composed of parametric terms (@onsite and @hopping) with ω as first argument, as in e.g. @onsite((ω, r) -> Σᵢᵢ(ω, r)) and @hopping((ω, r, dr) -> Σᵢⱼ(ω, r, dr))\n\nattach(h, nothing; sites...)\n\nAdd a nothing contact with a null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to labeling those sites with a contact number, but does not lead to any dressing the Green function. This is useful for some GreenFunction solvers such as GS.KPM (see greenfunction), which need to know the sites of interest beforehand (the contact sites in this case).\n\nattach(h, g1D::GreenFunction; reverse = false, transform = identity, sites...)\n\nAdd a self-energy Σ(ω) = h₋₁⋅g1D(ω)[surface]⋅h₁ corresponding to a semi-infinite 1D lead (i.e. with a finite boundary, see greenfunction), where h₁ and h₋₁ are intercell couplings, and g1D is the lead GreenFunction. The g1D(ω) is taken at the suface unitcell, either adjacent to the boundary on its positive side (if reverse = false) or on its negative side (if reverse = true). Note that reverse only flips the direction we extend the lattice to form the lead, but does not flip the unit cell (may use transform for that) or any contacts in the lead. The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the left or right unit cell surface of the lead (i.e. sites coupled to the adjacent unit cells), after applying transform to the latter. If they don't match, use the attach syntax below.\n\nAdvanced: If the g1D does not have any self-energies, the produced self-energy is in fact an ExtendedSelfEnergy, which is numerically more stable than a naive implementation of RegularSelfEnergy's, since g1D(ω)[surface] is never actually computed. Conversely, if g1D has self-energies attached, a RegularSelfEnergy is produced.\n\nattach(h, g1D::GreenFunction, coupling::AbstractModel; reverse = false, transform = identity, sites...)\n\nAdd a self-energy Σ(ω) = V´⋅g1D(ω)[surface]⋅V corresponding to a 1D lead (semi-infinite or infinite), but with couplings V and V´, defined by coupling, between sites and the surface lead unitcell (or the one with index zero if there is no boundary) . See also Advanced note above.\n\nCurrying\n\nh |> attach(args...; sites...)\n\nCurried form equivalent to attach(h, args...; sites...).\n\nExamples\n\njulia> # A graphene flake with two out-of-plane cubic-lattice leads\n\njulia> g1D = LP.cubic(names = :C) |> hamiltonian(hopping(1)) |> supercell((0,0,1), region = RP.square(4)) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> coupling = hopping(1, range = 2);\n\njulia> gdisk = HP.graphene(a0 = 1, dim = 3) |> supercell(region = RP.circle(10)) |> attach(g1D, coupling; region = RP.square(4)) |> attach(g1D, coupling; region = RP.square(4), reverse = true) |> greenfunction;\n\nSee also\n\n`greenfunction`, `GreenSolvers`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.bands","page":"API","title":"Quantica.bands","text":"bands(h::AbstractHamiltonian, xcolᵢ...; kw...)\n\nConstruct a Bandstructure object, which contains in particular a collection of continuously connected Subbands of h, obtained by diagonalizing the matrix h(ϕs; params...) on an M-dimensional mesh of points (x₁, x₂, ..., xₘ), where each xᵢ takes values in the collection xcolᵢ. The mapping between points in the mesh points and values of (ϕs; params...) is defined by keyword mapping (identity by default, see Keywords). Diagonalization is multithreaded and will use all available Julia threads (start session with julia -t N to have N threads).\n\nbands(f::Function, xcolᵢ...; kw...)\n\nLike the above using f(ϕs)::AbstractMatrix in place of h(ϕs; params...), and returning a Vector{<:Subband} instead of a Bandstructure object. This is provided as a lower level driver without the added slicing functionality of a full Bandstructure object, see below.\n\nbands(h::AbstractHamiltonian; kw...)\n\nEquivalent to bands(h::AbstractHamiltonian, xcolᵢ...; kw...) with a default xcolᵢ = subdiv(-π, π, 49).\n\nKeywords\n\nsolver: eigensolver to use for each diagonalization (see Eigensolvers). Default: ES.LinearAlgebra()\nmapping: a function of the form (x, y, ...) -> ϕs or (x, y, ...) -> ftuple(ϕs...; params...) that translates points (x, y, ...) in the mesh to Bloch phases ϕs or phase+parameter FrankenTuples ftuple(ϕs...; params...). See also linecuts below. Default: identity\ntransform: function to apply to each eigenvalue after diagonalization. Default: identity\ndegtol::Real: maximum distance between to nearby eigenvalue so that they are classified as degenerate. Default: sqrt(eps)\nsplit::Bool: whether to split bands into disconnected subbands. Default: true\nprojectors::Bool: whether to compute interpolating subspaces in each simplex (for use as GreenSolver). Default: true\nwarn::Bool: whether to emit warning when band dislocations are encountered. Default: true\nshowprogress::Bool: whether to show or not a progress bar. Default: true\ndefects: (experimental) a collection of extra points to add to the mesh, typically the location of topological band defects such as Dirac points, so that interpolation avoids creating dislocation defects in the bands. You need to also increase patches to repair the subband dislocations using the added defect vertices. Default: ()\npatches::Integer: (experimental) if a dislocation is encountered, attempt to patch it by searching for the defect recursively to a given order, or using the provided defects (preferred). Default: 0\n\nCurrying\n\nh |> bands(xcolᵢ...; kw...)\n\nCurried form of bands equivalent to bands(h, xcolᵢ...; kw...)\n\nBand linecuts\n\nTo do a linecut of a bandstructure along a polygonal path in the L-dimensional Brillouin zone, mapping a set of 1D points xs to a set of nodes, with pts interpolation points in each segment, one can use the following convenient syntax\n\nbands(h, subdiv(xs, pts); mapping = (xs => nodes))\n\nHere nodes can be a collection of SVector{L} or of named Brillouin zone points from the list (:Γ,:K, :K´, :M, :X, :Y, :Z). If mapping = nodes, then xs defaults to 0:length(nodes)-1. See also subdiv for its alternative methods.\n\nIndexing and slicing\n\nb[i]\n\nExtract i-th subband from b::Bandstructure. i can also be a Vector, an AbstractRange or any other argument accepted by getindex(subbands::Vector, i)\n\nb[slice::Tuple]\n\nCompute a section of b::Bandstructure with a \"plane\" defined by slice = (ϕ₁, ϕ₂,..., ϕₗ[, ϵ]), where each ϕᵢ or ϵ can be a real number (representing a fixed momentum or energy) or a : (unconstrained along that dimension). For bands of an L-dimensional lattice, slice will be padded to an L+1-long tuple with : if necessary. The result is a collection of of sliced Subbands.\n\nExamples\n\njulia> phis = range(0, 2pi, length = 50); h = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t));\n\njulia> bands(h(t = 1), phis, phis)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 5000\n Edges : 14602\n Simplices : 9588\n\njulia> bands(h, phis, phis; mapping = (x, y) -> ftuple(0, x; t = y/2π))\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 4950\n Edges : 14553\n Simplices : 9604\n\njulia> bands(h(t = 1), subdiv((0, 2, 3), (20, 30)); mapping = (0, 2, 3) => (:Γ, :M, :K))\nBandstructure{Float64,2,1}: 2D Bandstructure over a 1-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 97\n Edges : 96\n Simplices : 96\n\nSee also\n\n`spectrum`, `subdiv`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.bravais_matrix","page":"API","title":"Quantica.bravais_matrix","text":"bravais_matrix(lat::Lattice)\nbravais_matrix(h::AbstractHamiltonian)\n\nReturn the Bravais matrix of lattice lat or AbstractHamiltonian h, with Bravais vectors as its columns.\n\nExamples\n\njulia> lat = lattice(sublat((0,0)), bravais = ((1.0, 2), (3, 4)));\n\njulia> bravais_matrix(lat)\n2×2 SMatrix{2, 2, Float64, 4} with indices SOneTo(2)×SOneTo(2):\n 1.0 3.0\n 2.0 4.0\n\n\nSee also\n\n`lattice`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.combine","page":"API","title":"Quantica.combine","text":"combine(lats::Lattice...)\n\nIf all lats have compatible Bravais vectors, combine them into a single lattice. If necessary, sublattice names are renamed to remain unique.\n\ncombine(hams::Hamiltonians...; coupling = TighbindingModel())\n\nCombine a collection hams of Hamiltonians into one by combining their corresponding lattices, and optionally by adding a coupling between them, given by the hopping terms in coupling.\n\nNote that the coupling model will be applied to the combined lattice (which may have renamed sublattices to avoid name collissions). However, only hopping terms between different hams blocks will be applied.\n\nLimitations\n\nCurrently, combine only works with Lattice{T} AbstractHamiltonians{T} with the same T. Furthermore, if any of the hams is a ParametricHamiltonian or coupling is a ParametricModel, the sublattice names of all hams must be distinct. This ensures that parametric models, which get applied through Modifiers after construction of the ParametricHamiltonian, are not applied to the wrong sublattice, since sublattice names could be renamed by combine if they are not unique. Therefore, be sure to choose unique sublattice names upon construction for all the hams to be combined (see lattice).\n\nExamples\n\njulia> # Building Bernal-stacked bilayer graphene\n\njulia> hbot = HP.graphene(a0 = 1, dim = 3, names = (:A,:B));\n\njulia> htop = translate(HP.graphene(a0 = 1, dim = 3, names = (:C,:D)), (0, 1/√3, 1/√3));\n\njulia> h2 = combine(hbot, htop; coupling = hopping(1, sublats = :B => :C) |> plusadjoint)\nHamiltonian{Float64,3,2}: Hamiltonian on a 2D Lattice in 3D space\n Bloch harmonics : 5\n Harmonic size : 4 × 4\n Orbitals : [1, 1, 1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 14\n Coordination : 3.5\n\nSee also\n\n`hopping`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.conductance","page":"API","title":"Quantica.conductance","text":"conductance(gs::GreenSlice; nambu = false)\n\nGiven a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object G::Conductance representing the zero-temperature, linear, differential conductance Gᵢⱼ = dIᵢ/dVⱼ between contacts i and j at arbitrary bias ω = eV in units of e^2/h. Gᵢⱼ is given by\n\n Gᵢⱼ = e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱ-gʳΓⁱgᵃΓʲ]} (nambu = false)\n Gᵢⱼ = e^2/h × Tr{[im*δᵢⱼ(gʳ-gᵃ)Γⁱτₑ-gʳΓⁱτ₃gᵃΓʲτₑ]} (nambu = true)\n\nHere gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i. For Nambu systems (nambu = true), the matrices τₑ=[I 0; 0 0] and τ₃ = [I 0; 0 -I] ensure that charge reversal in Andreev reflections is properly taken into account. For normal systems (nambu = false), the total current at finite bias and temperatures is given by Iᵢ = eh dω ⱼ fᵢ(ω) - fⱼ(ω) Gᵢⱼ(ω), where fᵢ(ω) is the Fermi distribution in lead i.\n\nKeywords\n\nnambu : whether to consider the Hamiltonian of the system is written in a Nambu basis, each site containing N electron orbitals followed by N hole orbitals.\n\nFull evaluation\n\nG(ω; params...)\n\nCompute the conductance at the specified contacts.\n\nExamples\n\njulia> # A central system g0 with two 1D leads and transparent contacts\n\njulia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> G = conductance(g0[1])\nConductance{Float64}: Zero-temperature conductance dIᵢ/dVⱼ from contacts i,j, in units of e^2/h\n Current contact : 1\n Bias contact : 1\n\njulia> G(0.2) ≈ 3\ntrue\n\nSee also\n\n`greenfunction`, `ldos`, `current`, `josephson`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.current","page":"API","title":"Quantica.current","text":"current(h::AbstractHamiltonian; charge = -I, direction = 1)\n\nBuild an Operator object that behaves like a ParametricHamiltonian in regards to calls and getindex, but whose matrix elements are hoppings im*(rⱼ-rᵢ)direction*charge*tⱼᵢ, where tᵢⱼ are the hoppings in h. This operator is equal to hAᵢ, where Aᵢ is a gauge field along direction = i.\n\ncurrent(gs::GreenSlice; charge = -I, direction = missing)\n\nBuild Js::CurrentDensitySlice, a partially evaluated object representing the equilibrium local current density Jᵢⱼ(ω) at arbitrary energy ω from site j to site i, both taken from a specific lattice slice. The current is computed along a given direction (see Keywords).\n\ncurrent(gω::GreenSolution; charge = -I, direction = missing)\n\nBuild Jω::CurrentDensitySolution, as above, but for Jᵢⱼ(ω) at a fixed ω and arbitrary sites i, j. See also greenfunction for details on building a GreenSlice and GreenSolution.\n\nThe local current density is defined here as Jᵢⱼ(ω) = (2h) rᵢⱼ Re Tr(Hᵢⱼgⱼᵢ(ω) - gᵢⱼ(ω)Hⱼᵢ) * charge, with the integrated local current given by Jᵢⱼ = f(ω) Jᵢⱼ(ω) dω. Here Hᵢⱼ is the hopping from site j at rⱼ to i at rᵢ, rᵢⱼ = rᵢ - rⱼ, charge is the charge of carriers in orbital space (see Keywords), and gᵢⱼ(ω) is the retarded Green function between said sites.\n\nKeywords\n\ncharge : for multiorbital sites, charge can be a general matrix, which allows to compute arbitrary currents, such as spin currents.\ndirection: as defined above, Jᵢⱼ(ω) is a vector. If direction is missing the norm |Jᵢⱼ(ω)| is returned. If it is an u::Union{SVector,Tuple}, u⋅Jᵢⱼ(ω) is returned. If an n::Integer, Jᵢⱼ(ω)[n] is returned.\n\nFull evaluation\n\nJω[sites...]\nJs(ω; params...)\n\nGiven a partially evaluated Jω::CurrentDensitySolution or ρs::CurrentDensitySlice, build a sparse matrix Jᵢⱼ(ω) along the specified direction of fully evaluated local current densities.\n\nNote: Evaluating the current density returns a SparseMatrixCSC currently, instead of a OrbitalSliceMatrix, since the latter is designed for dense arrays.\n\nExample\n\njulia> # A semi-infinite 1D lead with a magnetic field `B`\n\njulia> g = LP.square() |> supercell((1,0), region = r->-2 hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> J = current(g[cells = SA[1]])\nCurrentDensitySlice{Float64} : current density at a fixed location and arbitrary energy\n charge : LinearAlgebra.UniformScaling{Int64}(-1)\n direction : missing\n\njulia> J(0.2; B = 0.1)\n3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n ⋅ 0.0290138 ⋅\n 0.0290138 ⋅ 0.0290138\n ⋅ 0.0290138 ⋅\n\njulia> J(0.2; B = 0.0)\n3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n ⋅ 7.77156e-16 ⋅\n 7.77156e-16 ⋅ 5.55112e-16\n ⋅ 5.55112e-16 ⋅\n\nSee also\n\n`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.decay_lengths","page":"API","title":"Quantica.decay_lengths","text":"Quantica.decay_lengths(g::GreenFunctionSchurLead, µ = 0; reverse = false)\nQuantica.decay_lengths(h::AbstractHamiltonian1D, µ = 0; reverse = false)\n\nCompute the decay lengths of evanescent modes of a 1D AbstractHamiltonian h or a 1D GreenFunction g using the GS.Schur solver. The modes decaying towards positive direction (relative to the Bravais vector) are used, unless reverse = true.\n\nExamples\n\njulia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));\n\njulia> Quantica.decay_lengths(h(U=2))\n1-element Vector{Float64}:\n 0.28364816427662776\n\nSee also:\n\n`Quantica.gaps`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.densitymatrix","page":"API","title":"Quantica.densitymatrix","text":"densitymatrix(gs::GreenSlice; opts...)\n\nCompute a ρ::DensityMatrix at thermal equilibrium on sites encoded in gs. The actual matrix for given system parameters params, and for a given chemical potential mu and temperature kBT is obtained by calling ρ(mu = 0, kBT = 0; params...). The algorithm used is specialized for the GreenSolver used, if available. In this case, opts are options for said algorithm.\n\ndensitymatrix(gs::GreenSlice, path::AbstractIntegrationPath; opts..., quadgk_opts...)\n\nAs above, but using a generic algorithm that relies on numerical integration of the Green function gs(ω) along a contour in the complex-ω plane, defined by the path object. See Paths for available paths. Most integration paths employ the Cauchy theorem, and therefore assume that gs(ω) is fully analytic between the path and the real axis. This may not be true if gs contains user-defined contacts created using attach(model) with general ω-dependent models, but note that Quantica will not check for analyticity. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine.\n\ndensitymatrix(gs::GreenSlice, ωscale::Real; kw...)\n\nAs above with path = Paths.radial(ωscale, π/4), which computes the density matrix by integrating the Green function from ω = -Inf to ω = Inf along a ϕ = π/4 radial complex path, see Paths for details. Here ωscale should correspond to some typical energy scale in the system, which dictates the speed at which we integrate the radial paths (the integration runtime may depend on ωscale, but not the result).\n\ndensitymatrix(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)\n\nAs above, but with a path = Paths.sawtooth(ωs), which uses a sawtooth-shaped path touching points ωs on the real axes. Ideally, these values should span the full system bandwidth.\n\nFull evaluation\n\nρ(μ = 0, kBT = 0; params...) # where ρ::DensityMatrix\n\nEvaluate the density matrix at chemical potential μ and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any. The result is given as an OrbitalSliceMatrix, see its docstring for further details.\n\nAlgorithms and keywords\n\nThe generic integration algorithm allows for the following opts (see also josephson):\n\nomegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.\ncallback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand evaluated at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.\n\nThe quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.\n\nCurrently, the following GreenSolvers implement dedicated densitymatrix algorithms:\n\nGS.Schur: based on numerical integration over Bloch phase. Boundaries and non-empty contacts are not currently supported. Assumes Hermitian Hamiltonian. No opts.\nGS.Spectrum: based on summation occupation-weigthed eigenvectors. No opts.\nGS.KPM: based on the Chebyshev expansion of the Fermi function. Currently only works for zero temperature and only supports nothing contacts (see attach). No opts.\n\nExample\n\njulia> g = HP.graphene(a0 = 1) |> supercell(region = RP.circle(10)) |> greenfunction(GS.Spectrum());\n\njulia> ρ = densitymatrix(g[region = RP.circle(0.5)])\nDensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver\n\njulia> ρ() # with mu = kBT = 0 by default\n2×2 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:\n 0.5+0.0im -0.262865+0.0im\n -0.262865+0.0im 0.5+0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.deserialize","page":"API","title":"Quantica.deserialize","text":"deserialize(as::AppliedSerializer, v; params...)\n\nConstruct h(; params...), where h = Quantica.parametric_hamiltonian(as) is the AbstractHamiltonian enclosed in as, with the matrix elements enconded in v = serialize(s) restored (i.e. overwritten). See serialize for details.\n\ndeserialize(m::OrbitalSliceArray, v)\n\nReconstruct an OrbitalSliceArray with the same structure as m but with the matrix elements enconded in v. This v is typically the result of a serialize call to a another similar m, but the only requirement is that is has the correct size. If v has the wrong eltype, it will be reintepreted to match the eltype of m.\n\nSee also\n\n`serializer`, `serialize`, `serialize!`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.deserialize!","page":"API","title":"Quantica.deserialize!","text":"deserialize!(as::AppliedSerializer, v; params...)\n\nIn-place version of deserialize. It returns h´ = Quantica.call!(h; params...) with serialised elements v restored (i.e. overwritten). Here h = Quantica.parent_hamiltonian(s) is the AbstractHamiltonian used to construct as. The resulting h´::Hamiltonian is not an independent copy, but is aliased with h.\n\nExamples\n\njulia> h = HP.graphene() |> supercell(2);\n\njulia> s = serializer(h)\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : Hamiltonian\n Object parameters : none\n Stream parameter : :stream\n Output eltype : ComplexF64\n Encoder/Decoder : Single\n Length : 24\n\njulia> h === deserialize!(s, serialize(s))\ntrue\n\njulia> h === deserialize(s, serialize(s))\nfalse\n\njulia> h == deserialize(s, serialize(s))\ntrue\n\nSee also\n\n`serializer`, `serialize`, `serialize!`, `deserialize`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.diagonal","page":"API","title":"Quantica.diagonal","text":"diagonal(i; kernel = missing)\n\nWrapper over site or orbital indices i (used to index into a g::GreenFunction or g::GreenSolution) that represent purely diagonal entries. Here i can be any index accepted in g[i,i], e.g. i::Integer (contact index), i::Colon (merged contacts), i::SiteSelector (selected sites), etc.\n\nIf kernel = Q (a matrix) instead of missing, each diagonal block for multiorbital site i is replaced with Tr(gᵢᵢQ).\n\nFor a gω::GreenSolution, gω[diagonal(sel)] = diag(gω[sel, sel]), although where possible the former computation is done more efficiently internally.\n\ndiagonal(; kernel = missing, sites...)\n\nEquivalent to diagonal(siteselector(; sites...); kernel)\n\nKeywords\n\n- `kernel`: if missing, all orbitals in the diagonal `g[i, i]` are returned when indexing `g[diagonal(i)]`. Otherwise, `Tr(g[site, site]*kernel)` for each site included in `i` is returned.\n\nExample\n\njulia> g = HP.graphene(orbitals = 2) |> attach(nothing, cells = (0,0)) |> greenfunction();\n\njulia> g(1)[diagonal(:)] # g(ω = 1) diagonal on all contact orbitals\n4×4 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:\n -0.10919-0.0839858im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im -0.10919-0.0839858im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im -0.10919-0.0839858im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im -0.10919-0.0839858im\n\njulia> g(1)[diagonal(:, kernel = SA[1 0; 0 -1])] # σz spin density of the above\n2×2 OrbitalSliceMatrix{ComplexF64,LinearAlgebra.Diagonal{ComplexF64, Vector{ComplexF64}}}:\n 5.61885e-12+1.38778e-17im 0.0+0.0im\n 0.0+0.0im -5.61882e-12+2.77556e-17im\n\nSee also\n\n`sitepairs`, `greenfunction`, `ldos`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.energies","page":"API","title":"Quantica.energies","text":"energies(sp::Spectrum)\n\nReturns the energies in sp as a vector of Numbers (not necessarily real). Equivalent to first(sp).\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.gap","page":"API","title":"Quantica.gap","text":"Quantica.gap(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)\n\nCompute the minimal gap around µ, see Quantica.gaps\n\nSee also:\n\n`Quantica.gaps`, `Quantica.decay_lengths`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.gaps","page":"API","title":"Quantica.gaps","text":"Quantica.gaps(h::Hamiltonian1D{T}, µ = 0; atol = eps(T), kw...)\n\nCompute the energy gaps of a 1D Hamiltonian h at chemical potential µ. The result is a Vector{T} of the local minima of the |ϵ(ϕ) - µ|, where ϵ(ϕ) is the energy band closest to µ and ϕ ∈ [-π,π] is the Bloch phase. The atol parameter is the absolute tolerance used to determine the local minima versus ϕ, which are computed using the Schur solver for 1D Hamiltonians. The keywords kw are passed to the ArnoldiMethod partialschur! eigensolver (kw = (; nev = 1) by default).\n\nThe LinearMaps and ArnoldiMethod packages must be loaded to enable this functionality.\n\nExamples\n\njulia> using LinearMaps, ArnoldiMethod\n\njulia> h = LP.linear() |> supercell(4) |> hopping(1) - @onsite((r; U = 2) -> ifelse(iseven(r[1]), U, -U));\n\njulia> Quantica.gaps(h(U=2))\n2-element Vector{Float64}:\n 1.9999999999999996\n 1.9999999999999991\n\nSee also:\n\n`Quantica.gap`, `Quantica.decay_lengths`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.greenfunction","page":"API","title":"Quantica.greenfunction","text":"greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::AbstractGreenSolver)\n\nBuild a g::GreenFunction of Hamiltonian h using solver. See GreenSolvers for available solvers. If solver is not provided, a default solver is chosen automatically based on the type of h.\n\nCurrying\n\nh |> greenfunction(solver)\n\nCurried form equivalent to greenfunction(h, solver).\n\nPartial evaluation\n\nGreenFunctions allow independent, partial evaluation of their positions (producing a GreenSlice) and energy/parameters (producing a GreenSolution). Depending on the solver, this may avoid repeating calculations unnecesarily when sweeping over either of these with the other fixed.\n\ng[ss]\ng[siteselector(; ss...)]\n\nBuild a gs::GreenSlice that represents a Green function at arbitrary energy and parameter values, but at specific sites on the lattice defined by siteselector(; ss...), with ss::NamedTuple (see siteselector).\n\ng[contact_index::Integer]\n\nBuild a GreenSlice equivalent to g[contact_sites...], where contact_sites... correspond to sites in contact number contact_index (must have 1<= contact_index <= number_of_contacts). See attach for details on attaching contacts to a Hamiltonian.\n\ng[:]\n\nBuild a GreenSlice over all contacts.\n\ng[dst, src]\n\nBuild a gs::GreenSlice between sites specified by src and dst, which can take any of the forms above. Therefore, all the previous single-index slice forms correspond to a diagonal block g[i, i].\n\ng[diagonal(i; kernel = missing)]\n\nBuild a diagonal gs::GreenSlice over sites specified by i. If kernel = missing the diagonal entries are g[o, o] for orbitals o in sites encoded in i. If kernel is a matrix, the diagonal elements are tr(g[site, site] * kernel) over each site i. Note that if there are several orbitals per site, g[site, site] may have different sizes (i.e. number of orbitals vs number of sites). Upon evaluating gs(ω), the result is a Diagonal matrix wrapped in an OrbitalSliceMatrix, and spans full unit cells.See also diagonal.\n\ng[sitepairs(; kernel = missing, hops...)]\n\nLike the above but for a selection of site pairs selected by hopselector(; hops...). Upon evaluating gs(ω), the result is a SparseMatrixCSC wrapped in an OrbitalSliceMatrix, and spans full unit cells. See also sitepairs.\n\ng(ω; params...)\n\nBuild a gω::GreenSolution that represents a retarded Green function at arbitrary points on the lattice, but at fixed energy ω and system parameter values param. If ω is complex, the retarded or advanced Green function is returned, depending on sign(imag(ω)). If ω is Real, a small, positive imaginary part is automatically added internally to produce the retarded g.\n\ngω[i]\ngω[i, j]\ngs(ω; params...)\n\nFor any gω::GreenSolution or gs::GreenSlice, build the Green function matrix fully evaluated at fixed energy, parameters and positions. The matrix is a dense m::OrbitalSliceMatrix with scalar element type, so that any orbital structure on each site is flattened. Note that the resulting m can itself be indexed over collections of sites with m[i, j], where i, j are siteselector(; ss...) or ss::NamedTuple.\n\nview(gω, i::C, j::C == i)\n\nFor any gω::GreenSolution and C<:Union{Colon,Integer}, obtain a view (of type SubArray, not OrbitalSliceMatrix) of the corresponding intra or inter-contact propagator gω[i, j] with minimal allocations.\n\ng(; params...)\n\nFor any g::Union{GreenFunction,GreenSlice}, produce a new GreenFunction or GreenSlice with all parameters fixed to params (or to their default values if not provided).\n\nFull evaluation\n\ngs(ω; params...)\ngω[sites...]\n\nFor gs::GreenSlice or gω::GreenSolution, return a fully evaluated m::AbstractMatrix. If the selected site slice was defined using sites, the concrete type of m will be will be a conventional Matrix-based type. Otherwise, it will be of type OrbitalSliceMatrix, an AbstractMatrix type that supports both conventional indexing and indexing with sites and siteselectors.\n\nAdvanced: in addition to the above, an unexported method Quantica.call!(gs, ω; params...) is provided to reuse the output matrix m (preallocated inside gs). Use with caution, as it may lead to unexpected aliasing\n\nExample\n\njulia> g = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t)) |> supercell(region = RP.circle(10)) |> greenfunction(GS.SparseLU())\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 0\n Contact solvers : ()\n Contact sizes : ()\n ParametricHamiltonian{Float64,2,0}: Parametric Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 726 × 726\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 2098\n Coordination : 2.88981\n Parameters : [:t]\n\njulia> gω = g(0.1; t = 2)\nGreenSolution{Float64,2,0}: Green function at arbitrary positions, but at a fixed energy\n\njulia> ss = (; region = RP.circle(2), sublats = :B);\n\njulia> gs = g[ss]\nGreenSlice{Float64,2,0}: Green function at arbitrary energy, but at a fixed lattice positions\n\njulia> gω[ss] == gs(0.1; t = 2)\ntrue\n\njulia> summary(gω[ss])\n\"14×14 OrbitalSliceMatrix{ComplexF64,Array}\"\n\nSee also\n\n`GreenSolvers`, `diagonal`, `sitepairs`, `ldos`, `conductance`, `current`, `josephson`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hamiltonian","page":"API","title":"Quantica.hamiltonian","text":"hamiltonian(lat::Lattice, model; orbitals = 1)\n\nCreate an AbstractHamiltonian (i.e. an Hamiltonian or ParametricHamiltonian) by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building parametric and non-parametric tight-binding models).\n\nhamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)\n\nCreate a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided parametric modifiers (see @onsite! and @hopping! for details on defining modifiers).\n\nhamiltonian(h::AbstractHamiltonian, modifier, modifiers...)\n\nAdd modifiers to an existing AbstractHamiltonian.\n\nhamiltonian(h::ParametricHamiltonian)\n\nReturn the base (non-parametric) Hamiltonian of h, with all modifiers and parametric model terms removed (see @onsite, @hopping, @onsite!, @hopping!).\n\nKeywords\n\norbitals: number of orbitals per sublattice. If an Integer (or a Val{<:Integer} for type-stability), all sublattices will have the same number of orbitals. A collection of values indicates the orbitals on each sublattice.\n\nCurrying\n\nlat |> hamiltonian(model[, modifiers...]; kw...)\n\nCurried form of hamiltonian equivalent to hamiltonian(lat, model, modifiers...; kw...).\n\nlat |> model\n\nAlternative and less general curried form equivalent to hamiltonian(lat, model).\n\nh |> modifier\n\nAlternative and less general curried form equivalent to hamiltonian(h, modifier).\n\nIndexing\n\nh[dn::SVector{L,Int}]\nh[dn::NTuple{L,Int}]\n\nReturn the Bloch harmonic of an h::AbstractHamiltonian in the form of a SparseMatrixCSC with complex scalar eltype. This matrix is \"flat\", in the sense that it contains matrix elements between individual orbitals, not sites. This distinction is only relevant for multiorbital Hamiltonians. To access the non-flattened matrix use h[unflat(dn)] (see also unflat).\n\nh[()]\n\nSpecial syntax equivalent to h[(0...)], which access the fundamental Bloch harmonic.\n\nh[i::CellSites, j::CellSites = i]\n\nWith i and j of type CellSites and constructed with sites([cell,] indices), return a SparseMatrixCSC block of h between the sites with the corresponding indices and in the given cells. Alternatively, one can also use view(h, i, j = i), which should be non-allocating for AbstractHamiltonians with uniform number of orbitals.\n\nh[srow::SiteSelector, scol::SiteSelector = srow]\nh[kwrow::NamedTuple, kwcol::NamedTuple = kwrow]\n\nReturn an OrbitalSliceMatrix of h between row and column sites selected by srow and scol, or by siteselector(; kwrow...) and siteselector(; kwcol...)\n\nNote: CellSites and SiteSelectors can be mixed when indexing, in which case the matrix block will be returned as a SparseMatrixCSC, instead of an OrbitalSliceMatrix.\n\nCall syntax\n\nph(; params...)\n\nReturn a h::Hamiltonian from a ph::ParametricHamiltonian by applying specific values to its parameters params. If ph is a non-parametric Hamiltonian instead, this is a no-op.\n\nh(φs; params...)\n\nReturn the flat, sparse Bloch matrix of h::AbstractHamiltonian at Bloch phases φs, with applied parameters params if h is a ParametricHamiltonian. The Bloch matrix is defined as\n\n H = ∑_dn exp(-im φs⋅dn) H_dn\n\nwhere H_dn = h[dn] is the dn flat Bloch harmonic of h, and φs[i] = k⋅aᵢ in terms of the wavevector k and the Bravais vectors aᵢ.\n\nExamples\n\njulia> h = hamiltonian(LP.honeycomb(), hopping(SA[0 1; 1 0], range = 1/√3), orbitals = 2)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> h((0,0))\n4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ 0.0+0.0im 3.0+0.0im\n ⋅ ⋅ 3.0+0.0im 0.0+0.0im\n 0.0+0.0im 3.0+0.0im ⋅ ⋅\n 3.0+0.0im 0.0+0.0im ⋅ ⋅\n\njulia> h[sites(1), sites(2)]\n2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 0.0+0.0im 1.0+0.0im\n 1.0+0.0im 0.0+0.0im\n\njulia> ph = h |> @hopping!((t; p = 3) -> p*t); ph[region = RP.square(1)]\n4×4 OrbitalSliceMatrix{ComplexF64,SparseMatrixCSC}:\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 3.0+0.0im\n 0.0+0.0im 0.0+0.0im 3.0+0.0im 0.0+0.0im\n 0.0+0.0im 3.0+0.0im 0.0+0.0im 0.0+0.0im\n 3.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n\nSee also\n\n`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`, `OrbitalSliceMatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hopping","page":"API","title":"Quantica.hopping","text":"hopping(t; hops...)\nhopping((r, dr) -> t(r, dr); hops...)\n\nBuild a TighbindingModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce an Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nhopping(m::Union{TighbindingModel,ParametricModel}; hops...)\n\nConvert m into a new model with just hopping terms acting on hops.\n\nModel algebra\n\nModels can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.\n\nExamples\n\njulia> model = hopping((r, dr) -> cis(dot(SA[r[2], -r[1]], dr)); dcells = (0,0)) + onsite(r -> rand())\nTightbindingModel: model with 2 terms\n HoppingTerm{Function}:\n Region : any\n Sublattice pairs : any\n Cell distances : (0, 0)\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n OnsiteTerm{Function}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 8 × 8\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 8\n Hoppings : 16\n Coordination : 2.0\n\nSee also\n\n`onsite`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`, `plusadjoint`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.hopselector","page":"API","title":"Quantica.hopselector","text":"hopselector(; range = neighbors(1), dcells = missing, sublats = missing, region = missing)\n\nReturn a HopSelector object that can be used to select a finite set of hops between sites in a lattice. Hops between two sites at positions r₁ = r - dr/2 and r₂ = r + dr, belonging to unit cells with a cell distance dn::SVector{L,Int} and to a sublattices with names s₁::Symbol and s₂::Symbol will be selected only if\n\n`region(r, dr) && (s₁ => s₂ in sublats) && (dcell in dcells) && (norm(dr) <= range)`\n\nIf any of these is missing it will not be used to constraint the selection.\n\nGeneralization\n\nWhile range is usually a Real, and sublats and dcells are usually collections of Pair{Symbol}s and SVectors, respectively, they also admit other possibilities:\n\nsublats = :A # Hops from :A to :A\nsublats = :A => :B # Hops from :A to :B sublattices, but not from :B to :A\nsublats = (:A => :B,) # Same as above\nsublats = (:A => :B, :C => :D) # Hopping from :A to :B or :C to :D\nsublats = (:A, :C) .=> (:B, :D) # Broadcasted pairs, same as above\nsublats = (:A, :C) => (:B, :D) # Direct product, (:A=>:B, :A=>:D, :C=>:B, :C=>D)\nsublats = 1 => 2 # Hops from 1st to 2nd sublat. All the above patterns also admit Ints\nsublats = (spec₁, spec₂, ...) # Hops matching any of the specs with any of the above forms\n\ndcells = dn::SVector{L,Integer} # Hops between cells separated by `dn`\ndcells = dn::NTuple{L,Integer} # Hops between cells separated by `SVector(dn)`\ndcells = f::Function # Hops between cells separated by `dn` such that `f(dn) == true`\n\nrange = neighbors(n) # Hops within the `n`-th nearest neighbor distance in the lattice\nrange = (min, max) # Hops at distance inside the `[min, max]` closed interval (bounds can also be `neighbors(n)`)\n\nUsage\n\nAlthough the constructor hopselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering hops, which themselves call hopselector internally as needed. Some of these functions are\n\n- hopping(...; kw...) : hopping model term to be applied to site pairs specified by `kw`\n- @hopping(...; kw...) : parametric hopping model term to be applied to site pairs specified by `kw`\n- @hopping!(...; kw...) : hopping modifier to be applied to site pairs specified by `kw`\n\nExamples\n\njulia> h = LP.honeycomb() |> hamiltonian(hopping(1, range = neighbors(2), sublats = (:A, :B) .=> (:A, :B)))\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 7\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 12\n Coordination : 6.0\n\njulia> h = LP.honeycomb() |> hamiltonian(hopping(1, range = (neighbors(2), neighbors(3)), sublats = (:A, :B) => (:A, :B)))\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 9\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 18\n Coordination : 9.0\n\nSee also\n\n`siteselector`, `lattice`, `hopping`, `@hopping`, `@hopping!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.integrand","page":"API","title":"Quantica.integrand","text":"Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0; params...)\n\nReturn the complex integrand d::JosephsonIntegrand whose integral over frequency yields the Josephson current, J(kBT; params...) = Re(∫dx d(x; params...)), where ω(x) = Quantica.point(x, d) is a path parametrization over real variable x . To evaluate the d for a given x and parameters, use d(x; params...), or call!(d, x; params...) for its mutating (non-allocating) version.\n\nQuantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0; params...)\n\nLike above for the density matrix ρ, with d::DensityMatrixIntegrand, so that ρ(mu, kBT; params...) = -mat_imag(∫dω d(ω; params...))/π, and mat_imag(GF::Matrix) = (GF - GF')/2im.\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.josephson","page":"API","title":"Quantica.josephson","text":"josephson(gs::GreenSlice, path::AbstractIntegrationPath; opts..., quadgk_opts...)\n\nFor a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a J::Josephson object representing the equilibrium (static) Josephson current I_J flowing into g through contact i. The algorithm relies on the integration of a function of gs(ω) (see below) along a contour in the complex-ω plane defined by path (see Paths for available options). Most integration paths employ the Cauchy theorem, and therefore assume that gs(ω) is fully analytic between the path and the real axis. This may not be true if gs contains user-defined contacts created using attach(model) with general ω-dependent models, but note that Quantica will not check for analyticity. Keywords quadgk_opts are passed to the QuadGK.quadgk integration routine.\n\nThe result of I_J is given in units of qe/h (q is the dimensionless carrier charge). I_J can be written as I_J = Re dω f(ω) j(ω), where j(ω) = (qeh) 2Tr(ΣʳᵢGʳ - GʳΣʳᵢ)τz. Here f(ω) is the Fermi function with µ = 0.\n\njosephson(gs::GreenSlice, ωscale::Real; kw...)\n\nAs above, but with path = Paths.radial(ωscale, π/4), which computes josephson current by integrating the Green function from ω = -Inf to ω = Inf along a ϕ = π/4 radial complex path, see Paths for details. Here ωscale should be some typical energy scale in the system, like the superconducting gap (the integration time may depend on ωscale, but not the result).\n\njosephson(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)\n\nAs above, but with a path = Paths.sawtooth(ωs), which uses a sawtooth-shaped path touching points ωs on the real axes. Ideally, these values should span the full system bandwidth.\n\nFull evaluation\n\nJ(kBT = 0; params...) # where J::Josephson\n\nEvaluate the current I_J at chemical potemtial µ = 0 and temperature kBT (in the same units as the Hamiltonian) for the given g parameters params, if any.\n\nKeywords\n\nThe generic integration algorithm allows for the following opts (see also densitymatrix):\n\nphases : collection of superconducting phase biases to apply to the contact, so as to efficiently compute the full current-phase relation [I_J(ϕ) for ϕ in phases]. Note that each phase bias ϕ is applied by a [cis(-ϕ/2)*I 0*I; 0*I cis(ϕ/2)*I] rotation to the self energy, which is almost free. If missing, a single I_J is returned.\nomegamap: a function ω -> (; params...) that translates ω at each point in the integration contour to a set of system parameters. Useful for ParametricHamiltonians which include terms Σ(ω) that depend on a parameter ω (one would then use omegamap = ω -> (; ω)). Default: ω -> (;), i.e. no mapped parameters.\ncallback: a function to be called as callback(x, y) at each point in the integration, where x is the contour point and y is the integrand at that point. Useful for inspection and debugging, e.g. callback(x, y) = @show x. Default: Returns(nothing).\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero. Default 1e-7.\n\nThe quadgk_opts are extra keyword arguments (other than atol) to pass on to the function QuadGK.quadgk that is used for the integration.\n\nExamples\n\njulia> glead = LP.square() |> hamiltonian(@onsite((; ω = 0) -> 0.0005 * SA[0 1; 1 0] + im*ω*I) + hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(SA[1 0; 0 -1]), orbitals = 2) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> J = josephson(g0[1], 0.0005; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))\nJosephson: equilibrium Josephson current at a specific contact using solver of type JosephsonIntegratorSolver\n\njulia> J(0.0)\n10-element Vector{Float64}:\n 1.0130103834038537e-15\n 0.0008178802022977883\n 0.0016109471548779466\n 0.0023551370133118215\n 0.0030278625151304614\n 0.003608696305848759\n 0.00407998998248311\n 0.0044274100715435295\n 0.004640372460465891\n 5.179773035314182e-12\n\nSee also\n\n`greenfunction`,`ldos`, `current`, `conductance`, `transmission`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.lattice","page":"API","title":"Quantica.lattice","text":"lattice(sublats::Sublat...; bravais = (), dim, type, names)\nlattice(sublats::AbstractVector{<:Sublat}; bravais = (), dim, type, names)\n\nCreate a Lattice{T,E,L} from sublattices sublats, where L is the number of Bravais vectors given by bravais, T = type is the AbstractFloat type of spatial site coordinates, and dim = E is the spatial embedding dimension.\n\nlattice(lat::Lattice; bravais = missing, dim = missing, type = missing, names = missing)\n\nCreate a new lattice by applying any non-missing keywords to lat.\n\nlattice(x)\n\nReturn the parent lattice of object x, of type e.g. LatticeSlice, Hamiltonian, etc.\n\nKeywords\n\nbravais: a collection of one or more Bravais vectors of type NTuple{E} or SVector{E}. It can also be an AbstractMatrix of dimension E×L. The default bravais = () corresponds to a bounded lattice with no Bravais vectors.\nnames: a collection of Symbols. Can be used to rename sublats. Any repeated names will be replaced if necessary by :A, :B etc. to ensure that all sublattice names are unique.\n\nIndexing\n\nlat[kw...]\nlat[siteselector(; kw...)]\n\nIndexing into a lattice lat with keywords returns LatticeSlice representing a finite collection of sites selected by siteselector(; kw...). See siteselector for details on possible kw, and sites to obtain site positions.\n\nlat[]\n\nSpecial case equivalent to lat[cells = (0,...)] that returns a LatticeSlice of the zero-th unitcell.\n\nlat[i::CellSites]\n\nWith an i of type CellSites contructed with sites([cell,] indices), return a LatticeSlice of the corresponding sites.\n\nExamples\n\njulia> lat = lattice(sublat((0, 0)), sublat((0, 1)); bravais = (1, 0), type = Float32, dim = 3, names = (:up, :down))\nLattice{Float32,3,1} : 1D lattice in 3D space\n Bravais vectors : Vector{Float32}[[1.0, 0.0, 0.0]]\n Sublattices : 2\n Names : (:up, :down)\n Sites : (1, 1) --> 2 total per unit cell\n\njulia> lattice(lat; type = Float64, names = (:A, :B), dim = 2)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 0.0]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (1, 1) --> 2 total per unit cell\n\nSee also\n\n`LatticePresets`, `sublat`, `sites`, `supercell`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.ldos","page":"API","title":"Quantica.ldos","text":"ldos(gs::GreenSlice; kernel = missing)\n\nBuild ρs::LocalSpectralDensitySlice, a partially evaluated object representing the local density of states ρᵢ(ω) at specific sites i but at arbitrary energy ω.\n\nldos(gω::GreenSolution; kernel = missing)\n\nBuild ρω::LocalSpectralDensitySolution, as above, but for ρᵢ(ω) at a fixed ω and arbitrary sites i. See also greenfunction for details on building a GreenSlice and GreenSolution.\n\nThe local density of states is defined here as ρᵢ(ω) = -Tr(gᵢᵢ(ω))π, where gᵢᵢ(ω) is the retarded Green function at a given site i.\n\nKeywords\n\nkernel : for multiorbital sites, kernel allows to compute a generalized ldos ρᵢ(ω) = -imag(Tr(gᵢᵢ(ω) * kernel))/π, where gᵢᵢ(ω) is the retarded Green function at site i and energy ω. If kernel = missing, the complete, orbital-resolved ldos is returned. Default: missing\n\nFull evaluation\n\nρω[sites...]\nρs(ω; params...)\n\nGiven a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build an OrbitalSliceVector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states. See OrbitalSliceVector for further details.\n\nExample\n\njulia> g = HP.graphene(a0 = 1, t0 = 1) |> supercell(region = RP.circle(20)) |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 300, bandrange = (-3.1, 3.1)))\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedKPMGreenSolver\n Contacts : 1\n Contact solvers : (SelfEnergyEmptySolver,)\n Contact sizes : (6,)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 2898 × 2898\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 8522\n Coordination : 2.94065\n\njulia> ldos(g(0.2))[1]\n6-element OrbitalSliceVector{Vector{Float64}}:\n 0.036802204179316955\n 0.034933055722650375\n 0.03493305572265026\n 0.03493305572265034\n 0.03493305572265045\n 0.036802204179317045\n\njulia> ldos(g(0.2))[1] == -imag.(diag(g[diagonal(1)](0.2))) ./ π\ntrue\n\nSee also\n\n`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`, `OrbitalSliceVector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.meanfield","page":"API","title":"Quantica.meanfield","text":"meanfield(g::GreenFunction, args...; kw...)\n\nBuild a M::MeanField object that can be used to compute the Hartree-Fock-Bogoliubov mean field Φ between selected sites interacting through a given charge-charge potential. The density matrix used to build the mean field is obtained with densitymatrix(g[pair_selection], args...; kw...), see densitymatrix for details.\n\nThe mean field between site i and j is defined as Φᵢⱼ = δᵢⱼ hartreeᵢ + fockᵢⱼ, where\n\nhartreeᵢ = ν * Q * Σ_k v_H(r_i-r_k) * tr(ρ[k,k]*Q)\nfockᵢⱼ = -v_F(r_i-r_j) * Q * ρ[i,j] * Q\n\nHere Q is the charge operator, v_H and v_F are Hartree and Fock interaction potentials, and ρ is the density matrix evaluated at specific chemical potential and temperature. Also ν = ifelse(nambu, 0.5, 1.0), and v_F(0) = v_H(0) = U, where U is the onsite interaction.\n\nKeywords\n\npotential: charge-charge potential to use for both Hartree and Fock. Can be a number or a function of position. Default: 1\nhartree: charge-charge potential v_H for the Hartree mean field. Can be a number or a function of position. Overrides potential. Default: potential\nfock: charge-charge potential v_F for the Fock mean field. Can be a number, a function of position or nothing. In the latter case all Fock terms (even onsite) will be dropped. Default: hartree\nonsite: charge-charge onsite potential. Overrides both Hartree and Fock potentials for onsite interactions. Default: hartree(0)\ncharge: a number (in single-orbital systems) or a matrix (in multi-orbital systems) representing the charge operator on each site. Default: I\nnambu::Bool: specifies whether the model is defined in Nambu space. In such case, charge should also be in Nambu space, typically SA[1 0; 0 -1] or similar. Default: false\nnamburotation::Bool: if nambu == true and spinful systems, specifies whether the spinor basis is [c↑, c↓, c↓⁺, -c↑⁺] (namburotation = true) or [c↑, c↓, c↑⁺, c↓⁺] (namburotation = false). Default: false\nselector::NamedTuple: a collection of hopselector directives that defines the pairs of sites (pair_selection above) that interact through the charge-charge potential. Default: (; range = 0) (i.e. onsite)\n\nAny additional keywords kw are passed to the densitymatrix function used to compute the mean field, see above\n\nEvaluation and Indexing\n\nM(µ = 0, kBT = 0; params...) # where M::MeanField\n\nBuild an Φ::CompressedOrbitalMatrix, which is a special form of OrbitalSliceMatrix that can be indexed at pairs of individual sites, e.g. ϕ[sites(2), sites(1)] to return an SMatrix. This type of matrix is less flexible than OrbitalSliceMatrix but is fully static, and can encode symmetries. Its features are implementation details and are bound to change. The returned Φ is just meant to be used in non-spatial models, see Examples below.\n\nExamples\n\njulia> model = hopping(I) - @onsite((i; phi = zerofield) --> phi[i]); # see zerofield docstring\n\njulia> g = LP.honeycomb() |> hamiltonian(model, orbitals = 2) |> supercell((1,-1)) |> greenfunction;\n\njulia> M = meanfield(g; selector = (; range = 1), charge = I, potential = 0.05)\nMeanField{SMatrix{2, 2, ComplexF64, 4}} : builder of Hartree-Fock-Bogoliubov mean fields\n Charge type : 2 × 2 blocks (ComplexF64)\n Hartree pairs : 14\n Mean field pairs : 28\n Nambu : false\n\njulia> phi0 = M(0.2, 0.3);\n\njulia> phi0[sites(1), sites(2)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.00109527+0.0im 0.0+0.0im\n 0.0+0.0im 0.00109527+0.0im\n\njulia> phi0[sites(1)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.296672+0.0im 0.0+0.0im\n 0.0+0.0im 0.296672+0.0im\n\njulia> phi1 = M(0.2, 0.3; phi = phi0);\n\njulia> phi1[sites(1), sites(2)] |> Quantica.chopsmall\n2×2 SMatrix{2, 2, ComplexF64, 4} with indices SOneTo(2)×SOneTo(2):\n 0.00307712+0.0im 0.0+0.0im\n 0.0+0.0im 0.00307712+0.0im\n\nSee also\n\n`zerofield`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.neighbors","page":"API","title":"Quantica.neighbors","text":"neighbors(n::Int)\n\nCreate a Neighbors(n) object that represents a hopping range to distances corresponding to the n-th nearest neighbors in a given lattice, irrespective of their sublattice. Neighbors at equal distance do not count towards n.\n\nneighbors(n::Int, lat::Lattice)\n\nObtain the actual nth-nearest-neighbot distance between sites in lattice lat.\n\nSee also\n\n`hopping`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.onsite","page":"API","title":"Quantica.onsite","text":"onsite(o; sites...)\nonsite(r -> o(r); sites...)\n\nBuild a TighbindingModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Models may be applied to a lattice lat to produce a Hamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nonsite(m::{TighbindingModel,ParametricModel}; sites...)\n\nConvert m into a new model with just onsite terms acting on sites.\n\nModel algebra\n\nModels can be combined using +, - and *, or conjugated with ', e.g. onsite(1) - 2 * hopping(1)'.\n\nExamples\n\njulia> model = onsite(r -> norm(r) * SA[0 1; 1 0]; sublats = :A) - hopping(I; range = 2)\nTightbindingModel: model with 2 terms\n OnsiteTerm{Function}:\n Region : any\n Sublattices : A\n Cells : any\n Coefficient : 1\n HoppingTerm{LinearAlgebra.UniformScaling{Bool}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : 2.0\n Reverse hops : false\n Coefficient : -1\n\njulia> LP.cubic() |> supercell(4) |> hamiltonian(model, orbitals = 2)\nHamiltonian{Float64,3,3}: Hamiltonian on a 3D Lattice in 3D space\n Bloch harmonics : 27\n Harmonic size : 64 × 64\n Orbitals : [2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 64\n Hoppings : 2048\n Coordination : 32.0\n\nSee also\n\n`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.orbaxes","page":"API","title":"Quantica.orbaxes","text":"orbaxes(A::OrbitalSliceArray)\n\nReturn the orbital axes of A. This is a tuple of OrbitalSliceGrouped objects that can be used e.g. to index another OrbitalSliceArray or to inspect the indices of each site with siteindexdict.\n\nExamples\n\njulia> g = HP.graphene(orbitals = 2) |> supercell((1,-1)) |> greenfunction;\n\njulia> d = ldos(g[cells = SA[0]])(2); summary(d)\n\"8-element OrbitalSliceVector{Float64,Array}\"\n\njulia> a = only(orbaxes(d))\nOrbitalSliceGrouped{Float64,2,1} : collection of subcells of orbitals (grouped by sites) for a 1D lattice in 2D space\n Cells : 1\n Cell range : ([0], [0])\n Total sites : 4\n\njulia> siteindexdict(a)\n4-element Dictionaries.Dictionary{Quantica.CellIndices{1, Int64, Quantica.SiteLike}, UnitRange{Int64}}\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 1 │ 1:2\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 2 │ 3:4\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 3 │ 5:6\n CellSites{1,Int64} : 1 site in cell zero\n Sites : 4 │ 7:8\n\nSee also\n\n`siteindexdict`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.plusadjoint","page":"API","title":"Quantica.plusadjoint","text":"plusadjoint(t::Model)\n\nReturns a model t + t'. This is a convenience function analogous to the + h.c. notation.\n\nExample\n\njulia> model = hopping(im, sublats = :A => :B) |> plusadjoint\nTightbindingModel: model with 2 terms\n HoppingTerm{Complex{Bool}}:\n Region : any\n Sublattice pairs : :A => :B\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n HoppingTerm{Complex{Int64}}:\n Region : any\n Sublattice pairs : :A => :B\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : true\n Coefficient : 1\n\njulia> h = hamiltonian(LP.honeycomb(), model)\nHamiltonian{Float64,2,2}: Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 6\n Coordination : 3.0\n\njulia> h((0,0))\n2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 0.0-3.0im\n 0.0+3.0im ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.points","page":"API","title":"Quantica.points","text":"Quantica.points(O::Josephson, args...)\nQuantica.points(O::DensityMatrix, args...)\n\nReturn the vertices of the integration path used to compute O(args...).\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serialize","page":"API","title":"Quantica.serialize","text":"serialize(as::AppliedSerializer{T}; params...)\n\nConstruct a Vector{T} that encodes a selection of matrix elements of h(; params...) where h = Quantica.parent_hamiltonian(as) is the AbstractHamiltonian used to build the AppliedSerializer, see serializer.\n\nserialize(m::OrbitalSliceArray)\n\nReturn an Array of the same eltype as m that contains all the stored matrix elements of m. See deserialize for the inverse operation.\n\nserialize(T::Type, m::OrbitalSliceArray)\n\nReinterpret serialize(m) as a collection with eltype T\n\nSee also\n\n`serializer`, `serialize!`, `deserialize`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serialize!","page":"API","title":"Quantica.serialize!","text":"serialize!(v, as::AppliedSerializer; params...)\n\nFill v in-place with the output of serialize(as; params...), see serialize for details.\n\nSee also\n\n`serialize`, `serialize!`, `deserialize`, `deserialize!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.serializer","page":"API","title":"Quantica.serializer","text":"serializer(T::Type, selectors...; parameter = :stream, encoder = identity, decoder = identity)\n\nConstruct a abstract s::Serializer object defines the rules to serialize and deserialize an AbstractHamiltonian, i.e. to translate the matrix elements selected by selectors (SiteSelectors or HopSelectors) into a 1D array of scalars of type T.\n\nserializer(T::Type; kw...)\n\nEquivalent to serializer(T, siteselector(), hopselector(); kw...), i.e. with all onsites and hoppings included in selection.\n\nserializer(T::Type, h::AbstractHamiltonian, selectors...; kw...)\n\nApplies a Serializer object like those above, and applies it to h::AbstractHamiltonian to produce an AppliedSerializer{T,<:AbstractHamiltonian}, that can be used to serialize and deserialize h. See serialize and deserialize for further details.\n\nserializer(h::AbstractHamiltonian{T}, selectors...; kw...)\n\nEquivalent to serializer(Complex{T}, h, selectors...; kw...).\n\nKeywords\n\nparameter: the parameter name used to address the serialized vector after transforming an AppliedSerializer into a ParametricHamiltonian, see below. Default: :stream.\nencoder: a function s -> vec that translates a single matrix element s into an collection vec of scalars of type T. Also supported is encoder = (s->vec, (s,s´)->vec´), which applies the second function to hoppings hᵢⱼ = s and their adjoint hⱼᵢ = s´ to encode both in a single collection vec´ (onsites hᵢᵢ are still encoded using the first single-argument function). This is useful for Hermitian Hamiltonians, where hⱼᵢ can be derived from hᵢⱼ. Default: identity.\ndecoder: the inverse function vec -> s of the encoder. If encoder is a tuple, decoder should also be a tuple of the inverse functions of each encoder function. Default: identity.\n\nNote: for an h::AbstractHamiltonian with a non-uniform number of orbitals, the matrix element passed to the encoder should always be assumed to be a square SMatrix of a fixed size that can fit all sites, padded with zeros if necessary (see \"Element type\" when displaying it, and the output of h[unflat(dn)]). Likewise, the decoder should return a square SMatrix of the same size, or any other container that can be converted to one. The latter is also important in cases with a uniform orbital number greater than one (non-scalar element type).\n\nThe user can check that the encoder and decoder are mutual inverses with Quantica.check(s; params...) where params is any choice of Hamiltonian parameters. This essentially checks that h(; params) == deserialize(s, serialize(s; params...); params...) holds.\n\nCall syntax and ParametricHamiltonians\n\nas(; params...)\n\nTransforms as::AppliedSerializer{T,<:ParametricHamiltonian} into an as´::AppliedSerializer{T,<:Hamiltonian} where the enclosed h is replaced by h´ = h(; params...). The in-place (aliasing) version of the above is Quantica.call!(as; params...). Note that the enclosed AbstractHamiltonians can be retrieved with e.g. Quantica.parent_hamiltonian(as).\n\nhamiltonian(as::AppliedSerializer)\n\nBuilds a ph::ParametricHamiltonian by adding as as a parametric modifier (similar to @onsite! or @hopping!) to the h::AbstractHamiltonian enclosed in as. As a result, ph acquires a new parameter of the name given by the parameter keyword specified originally (:stream by default, see above). This parameter takes a serialized stream (e.g. the output of serialize(as)) and replaces the corresponding elements in ph.\n\nh |> s\n\nFor s::Serializer and h::AbstractHamiltonian, converts s into an as::AppliedSerializer by applying it to h and then adds as as a parametric modifier to h to produce a ph::ParametricHamiltonian, as above. Note that h |> as with as::AppliedSerializer is not allowed, since as can only be a modifier of its enclosed AbstractHamiltonian.\n\nExamples\n\njulia> h1 = LP.linear() |> hopping((r, dr) -> im*dr[1]) - @onsite((r; U = 2) -> U);\n\njulia> as = serializer(Float64, h1; encoder = s -> reim(s), decoder = v -> complex(v[1], v[2]))\nAppliedSerializer : translator between a selection of of matrix elements of an AbstractHamiltonian and a collection of scalars\n Object : ParametricHamiltonian\n Object parameters : [:U]\n Stream parameter : :stream\n Output eltype : Float64\n Encoder/Decoder : Single\n Length : 6\n\njulia> v = serialize(as; U = 4)\n6-element Vector{Float64}:\n -4.0\n 0.0\n -0.0\n -1.0\n 0.0\n 1.0\n\njulia> h2 = deserialize!(as, v);\n\njulia> h2 == h1(U = 4)\ntrue\n\njulia> h3 = hamiltonian(as)\nParametricHamiltonian{Float64,1,1}: Parametric Hamiltonian on a 1D Lattice in 1D space\n Bloch harmonics : 3\n Harmonic size : 1 × 1\n Orbitals : [1]\n Element type : scalar (ComplexF64)\n Onsites : 1\n Hoppings : 2\n Coordination : 2.0\n Parameters : [:U, :stream]\n\njulia> h3(stream = v, U = 5) == h1(U = 4) # stream overwrites the U=5 onsite terms\ntrue\n\nSee also\n\n`serialize`, `serialize!`, `deserialize`, `deserialize!`, `siteselector`, `hopselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.siteindexdict","page":"API","title":"Quantica.siteindexdict","text":"siteindexdict(axis::OrbitalSliceGrouped)\n\nReturn a dictionary of CellSites representing single sites in an orbital axis of an OrbitalSliceArray, typically obtained with orbaxes. See orbaxes for an example.\n\nSee also\n\n`orbaxes`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sitepairs","page":"API","title":"Quantica.sitepairs","text":"sitepairs(s::HopSelector; kernel = missing)\n\nCreate a selection of site pairs s::SparseIndices used to sparsely index into a g::GreenFunction or g::GreenSolution, as g[s]. Of the resulting OrbitalSliceMatrix only the selected pairs of matrix elements will be computed, leaving the rest as zero (sparse matrix). The sparse matrix spans the minimum number of complete unit cells to include all site pairs\n\nIf kernel = Q (a matrix instead of missing), each of these site blocks gᵢⱼ will be replaced by Tr(kernel * gᵢⱼ).\n\nsitepairs(; kernel = missing, hops...)\n\nEquivalent to sitepairs(hopselector(; hops...); kernel)\n\nKeywords\n\n- `kernel`: if missing, all orbitals blocks `gᵢⱼ = g[i, j]` between selected sites pairs (i,j) are returned when indexing `g[sitepairs(...)]`. Otherwise, `gᵢⱼ` is replaced by `Tr(gᵢⱼ*kernel)`.\n\nExample\n\njulia> g = HP.graphene(orbitals = 2, a0 = 1) |> attach(nothing, cells = (0,0)) |> greenfunction();\n\njulia> summary(g(1)[sitepairs(range = 1)]) # g(ω=1) site blocks between all sites in zero cell and all other sites at distance 1\n\"28×4 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}\"\n\njulia> summary(g(1)[sitepairs(range = 1, kernel = SA[1 0; 0 -1])]) # σz spin density of the above\n\"14×2 OrbitalSliceMatrix{ComplexF64,SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}\"\n\nSee also\n\n`diagonal`, `hopselector`, `greenfunction`, `ldos`, `densitymatrix`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sites","page":"API","title":"Quantica.sites","text":"sites(lat::Lattice[, sublat])\n\nReturn a collection of site positions in the unit cell of lattice lat. If a sublat::Symbol or sublat::Int is specified, only sites for the specified sublattice are returned.\n\nsites(ls::LatticeSlice)\n\nReturn a collection of positions of a LatticeSlice, generally obtained by indexing a lattice lat[sel...] with some siteselector keywords sel. See also lattice.\n\nNote: the returned collections can be of different types (vectors, generators, views...)\n\nsites(cell_index, site_indices)\nsites(site_indices)\n\nConstruct a simple selector of sites, of type CellSites, with given site_indices in a given cell at cell_index. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_index should be a collection of L integers, where L is the lattice dimension. If omitted, cell_index defaults to the zero-th cell (0,...).\n\nCellSites produced with sites can be used to index Lattices, AbstractHamiltonians, GreenFunctions, GreenSlices, OrbitalSliceArrays, etc. Note that selecting sites based on cell and site indices requires finding the indices beforehand, which can be done e.g. through plotting the system with qplot. This is lower level and potentially more fragile than using siteselectors, as indices are chosen freely by Quantica in an unspecified way, but it does have a smaller overhead.\n\nExamples\n\njulia> sites(LatticePresets.honeycomb(), :A)\n1-element view(::Vector{SVector{2, Float64}}, 1:1) with eltype SVector{2, Float64}:\n [0.0, -0.2886751345948129]\n\nSee also\n\n`lattice`, `siteselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.siteselector","page":"API","title":"Quantica.siteselector","text":"siteselector(; region = missing, sublats = missing, cells = missing)\n\nReturn a SiteSelector object that can be used to select a finite set of sites in a lattice. Sites at position r::SVector{E}, belonging to a cell of index n::SVector{L,Int} and to a sublattice with name s::Symbol will be selected only if\n\n`region(r) && s in sublats && n in cells`\n\nAny missing region, sublat or cells will not be used to constraint the selection.\n\nGeneralization\n\nWhile sublats and cells are usually collections of Symbols and SVectors, respectively, they also admit other possibilities:\n\nIf either cells or sublats are a single cell or sublattice, they will be treated as single-element collections\nIf sublat is a collection of Integers, it will refer to sublattice numbers.\nIf cells is an i::Integer, it will be converted to an SVector{1}\nIf cells is a collection, each element will be converted to an SVector.\nIf cells is a boolean function, n in cells will be the result of cells(n)\n\nUsage\n\nAlthough the constructor siteselector(; kw...) is exported, the end user does not usually need to call it directly. Instead, the keywords kw are input into different functions that allow filtering sites, which themselves call siteselector internally as needed. Some of these functions are\n\ngetindex(lat::Lattice; kw...) : return a LatticeSlice with sites specified by kw (also lat[kw...])\nsupercell(lat::Lattice; kw...) : returns a bounded lattice with the sites specified by kw\nonsite(...; kw...) : onsite model term to be applied to sites specified by kw\n@onsite!(...; kw...) : onsite modifier to be applied to sites specified by kw\n\nSee also\n\n`hopselector`, `lattice`, `supercell`, `onsite`, `@onsite`, `@onsite!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.spectrum","page":"API","title":"Quantica.spectrum","text":"spectrum(h::AbstractHamiltonian, ϕs; solver = EigenSolvers.LinearAlgebra(), transform = missing, params...)\n\nCompute the Spectrum of the Bloch matrix h(ϕs; params...) using the specified eigensolver, with transform applied to the resulting eigenenergies, if not missing. Eigenpairs are sorted by the real part of their energy. See EigenSolvers for available solvers and their options.\n\nspectrum(h::AbstractHamiltonian; kw...)\n\nFor a 0D h, equivalent to spectrum(h, (); kw...)\n\nspectrum(m::AbstractMatrix; solver = EigenSolvers.LinearAlgebra()], transform = missing)\n\nCompute the Spectrum of matrix m using solver and transform.\n\nspectrum(b::Bandstructure, ϕs)\n\nCompute the Spectrum corresponding to slicing the bandstructure b at point ϕs of its base mesh (see bands for details).\n\nIndexing and destructuring\n\nEigenenergies ϵs::Tuple and eigenstates ψs::Matrix can be extracted from a spectrum sp using any of the following\n\nϵs, ψs = sp\nϵs = first(sp)\nϵs = energies(sp)\nψs = last(sp)\nψs = states(sp)\n\nIn addition, one can extract the n eigenpairs closest (in real energy) to a given energy ϵ₀ with\n\nϵs, ψs = sp[1:n, around = ϵ₀]\n\nMore generally, sp[inds, around = ϵ₀] will take the eigenpairs at position given by inds after sorting by increasing distance to ϵ₀, or the closest eigenpair in inds is missing. If around is omitted, the ordering in sp is used.\n\nExamples\n\njulia> h = HP.graphene(t0 = 1); spectrum(h, (0,0))\nSpectrum{Float64,ComplexF64} :\nEnergies:\n2-element Vector{ComplexF64}:\n -2.9999999999999982 + 0.0im\n 2.9999999999999982 + 0.0im\nStates:\n2×2 Matrix{ComplexF64}:\n -0.707107+0.0im 0.707107+0.0im\n 0.707107+0.0im 0.707107+0.0im\n\nSee also\n\n`EigenSolvers`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.states","page":"API","title":"Quantica.states","text":"states(sp::Spectrum)\n\nReturns the eigenstates in sp as columns of a matrix. Equivalent to last(sp).\n\nSee also\n\n`spectrum`, `bands`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.subdiv","page":"API","title":"Quantica.subdiv","text":"subdiv((x₁, x₂, ..., xₙ), (p₁, p₂, ..., pₙ₋₁))\n\nBuild a vector of values between x₁ and xₙ containing all xᵢ such that in each interval [xᵢ, xᵢ₊₁] there are pᵢ equally space values.\n\nsubdiv((x₁, x₂, ..., xₙ), p)\n\nSame as above with all pᵢ = p\n\nsubdiv(x₁, x₂, p)\n\nEquivalent to subdiv((x₁, x₂), p) == collect(range(x₁, x₂, length = p))\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.sublat","page":"API","title":"Quantica.sublat","text":"sublat(sites...; name::Symbol = :A)\nsublat(sites::AbstractVector; name::Symbol = :A)\n\nCreate a Sublat{E,T} that adds a sublattice, of name name, with sites at positions sites in E dimensional space. Sites positions can be entered as Tuples or SVectors.\n\nExamples\n\njulia> sublat((0.0, 0), (1, 1), (1, -1), name = :A)\nSublat{2,Float64} : sublattice of Float64-typed sites in 2D space\n Sites : 3\n Name : :A\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.supercell","page":"API","title":"Quantica.supercell","text":"supercell(lat::Lattice{E,L}, v::NTuple{L,Integer}...; seed = missing, kw...)\nsupercell(lat::Lattice{E,L}, uc::SMatrix{L,L´,Int}; seed = missing, kw...)\n\nGenerate a new Lattice from an L-dimensional lattice lat with a larger unit cell, such that its Bravais vectors are br´= br * uc. Here uc::SMatrix{L,L´,Int} is the integer supercell matrix, with the L´ vectors vs as its columns. If no v are given, the new lattice will have no Bravais vectors (i.e. it will be bounded, with its shape determined by keywords kw...). Likewise, if L´ < L, the resulting lattice will be bounded along L´ - L directions, as dictated by kw....\n\nOnly sites selected by siteselector(; kw...) will be included in the supercell (see siteselector for details on the available keywords kw). If no keyword region is given in kw, a single Bravais unit cell perpendicular to the v axes will be selected along the L-L´ bounded directions.\n\nsupercell(lattice::Lattice{E,L}, factors::Integer...; seed = missing, kw...)\n\nCall supercell with different scaling along each Bravais vector, so that supercell matrix uc is Diagonal(factors). If a single factor is given, uc = SMatrix{L,L}(factor * I)\n\nsupercell(h::Hamiltonian, v...; mincoordination = 0, seed = missing, kw...)\n\nTransform the Lattice of h to have a larger unit cell, while expanding the Hamiltonian accordingly.\n\nKeywords\n\nseed::NTuple{L,Integer}: starting cell index to perform search of included sites. By default seed = missing, which makes search start from the zero-th cell.\nmincoordination::Integer: minimum number of nonzero hopping neighbors required for sites to be included in the supercell. Sites with less coordination will be removed recursively, until all remaining sites satisfy mincoordination.\n\nCurrying\n\nlat_or_h |> supercell(v...; kw...)\n\nCurried syntax, equivalent to supercell(lat_or_h, v...; kw...)\n\nExamples\n\njulia> LatticePresets.square() |> supercell((1, 1), region = r -> 0 < r[1] < 5)\nLattice{Float64,2,1} : 1D lattice in 2D space\n Bravais vectors : [[1.0, 1.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (8,) --> 8 total per unit cell\n\njulia> LatticePresets.honeycomb() |> supercell(3)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[1.5, 2.598076], [-1.5, 2.598076]]\n Sublattices : 2\n Names : (:A, :B)\n Sites : (9, 9) --> 18 total per unit cell\n\nSee also\n\n`supercell`, `siteselector`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.torus","page":"API","title":"Quantica.torus","text":"torus(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))\n\nFor an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new h´::AbstractHamiltonian on a bounded torus, i.e. with all Bravais vectors eliminated by stitching the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along stitched directions will pick up a Bloch phase exp(-iϕ⋅dn).\n\nIf a number L´ of phases ϕᵢ are : instead of numbers, the corresponding Bravais vectors will not be stitched, and the resulting h´ will have a finite lattice dimension L´.\n\nCurrying\n\nh |> torus((ϕ₁, ϕ₂,...))\n\nCurrying syntax equivalent to torus(h, (ϕ₁, ϕ₂,...)).\n\nExamples\n\njulia> h2D = HP.graphene(); h1D = torus(h2D, (:, 0.2))\nHamiltonian{Float64,2,1}: Hamiltonian on a 1D Lattice in 2D space\n Bloch harmonics : 3\n Harmonic size : 2 × 2\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 4\n Coordination : 2.0\n\njulia> h2D((0.3, 0.2)) ≈ h1D(0.3)\ntrue\n\nSee also\n\n`hamiltonian`, `supercell`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.transform","page":"API","title":"Quantica.transform","text":"transform(lat_or_h::Union{Lattice,AbstractHamiltonian}, f::Function)\n\nBuild a new lattice or hamiltonian transforming each site positions r into f(r).\n\nCurrying\n\nx |> transform(f::Function)\n\nCurried version of transform, equivalent to transform(f, x)\n\nNote: Unexported Quantica.transform! is also available for in-place transforms. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.\n\nExamples\n\njulia> LatticePresets.square() |> transform(r -> 3r)\nLattice{Float64,2,2} : 2D lattice in 2D space\n Bravais vectors : [[3.0, 0.0], [0.0, 3.0]]\n Sublattices : 1\n Names : (:A,)\n Sites : (1,) --> 1 total per unit cell\n\nSee also\n\n`translate`, `reverse`, `reverse!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.translate","page":"API","title":"Quantica.translate","text":"translate(lat::Lattice, δr)\n\nBuild a new lattice translating each site positions from r to r + δr, where δr can be a NTuple or an SVector in embedding space.\n\nCurrying\n\nx |> translate(δr)\n\nCurried version of translate, equivalent to translate(x, δr)\n\nNote: Unexported Quantica.translate! is also available for in-place translations. Use with care, as aliasing (i.e. several objects sharing the modified one) can produce unexpected results.\n\nExamples\n\njulia> LatticePresets.square() |> translate((3,3)) |> sites\n1-element Vector{SVector{2, Float64}}:\n [3.0, 3.0]\n\n\nSee also\n\n`transform`, `reverse`, `reverse!`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.transmission","page":"API","title":"Quantica.transmission","text":"transmission(gs::GreenSlice)\n\nGiven a slice gs = g[i::Integer, j::Integer] of a g::GreenFunction, build a partially evaluated object T::Transmission representing the normal transmission probability Tᵢⱼ(ω) from contact j to i at energy ω. It can be written as Tᵢⱼ = TrgʳΓⁱgᵃΓʲ. Here gʳ = g(ω) and gᵃ = (gʳ)' = g(ω') are the retarded and advanced Green function of the system, and Γⁱ = im * (Σⁱ - Σⁱ') is the decay rate at contact i\n\nFull evaluation\n\nT(ω; params...)\n\nCompute the transmission Tᵢⱼ(ω) at a given ω and for the specified params of g.\n\nExamples\n\njulia> # A central system g0 with two 1D leads and transparent contacts\n\njulia> glead = LP.square() |> hamiltonian(hopping(1)) |> supercell((1,0), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.square() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> T = transmission(g0[2, 1])\nTransmission: total transmission between two different contacts\n From contact : 1\n To contact : 2\n\njulia> T(0.2) ≈ 3 # The difference from 3 is due to the automatic `im*sqrt(eps(Float64))` added to `ω`\nfalse\n\njulia> T(0.2 + 1e-10im) ≈ 3\ntrue\n\nSee also\n\n`greenfunction`, `conductance`, `ldos`, `current`, `josephson`\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.unflat","page":"API","title":"Quantica.unflat","text":"unflat(dn)\n\nConstruct an u::Unflat object wrapping some indices dn. This object is meant to be used to index into a h::AbstractHamiltonian as h[u], which returns an non-flattened version of the Bloch harmonic h[dn]. Each element in the matrix h[u] is an SMatrix block representing onsite or hoppings between whole sites, in contrast to h[dn] where they are scalars representing single orbitals. This is only relevant for multi-orbital Hamiltonians h.\n\nunflat()\n\nEquivalent to unflat(())\n\nExamples\n\njulia> h = HP.graphene(orbitals = 2); h[unflat(0,0)]\n2×2 SparseArrays.SparseMatrixCSC{SMatrix{2, 2, ComplexF64, 4}, Int64} with 2 stored entries:\n ⋅ [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]\n [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im] ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#Quantica.@hopping","page":"API","title":"Quantica.@hopping","text":"@hopping((; params...) -> t(; params...); hops...)\n@hopping((r, dr; params...) -> t(r; params...); hops...)\n\nBuild a ParametricModel representing a uniform or a position-dependent hopping amplitude, respectively, on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. Hopping amplitudes t can be a Number (for hops between single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of site orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nThe difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.\n\n@hopping((ω; params...) -> Σᵢⱼ(ω; params...); hops...)\n@hopping((ω, r, dr; params...) -> Σᵢⱼ(ω, r, dr; params...); hops...)\n\nSpecial form of a parametric hopping amplitude meant to model a self-energy (see attach).\n\n@hopping((i, j; params...) --> ...; sites...)\n@hopping((ω, i, j; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nModel algebra\n\nParametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.\n\nExamples\n\njulia> model = @hopping((r, dr; t = 1, A = Returns(SA[0,0])) -> t * cis(-dr' * A(r)))\nParametricModel: model with 1 term\n ParametricHoppingTerm{ParametricFunction{2}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n Argument type : spatial\n Parameters : [:t, :A]\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 8 × 8\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 24\n Coordination : 3.0\n Parameters : [:A, :t]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@hopping!","page":"API","title":"Quantica.@hopping!","text":"@hopping!((t; params...) -> t´(t; params...); hops...)\n@hopping!((t, r, dr; params...) -> t´(t, r, dr; params...); hops...)\n\nBuild a uniform or position-dependent hopping term modifier, respectively, acting on hops selected by hopselector(; hops...) (see hopselector for details).\n\nHops from a site at position r₁ to another at r₂ are described using the hop center r = (r₁ + r₂)/2 and the hop vector dr = r₂ - r₁. The original hopping amplitude is t, and the modified hopping is t´, which is a function of t and possibly r, dr. It may optionally also depend on parameters, enconded in params.\n\nModifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.\n\n@hopping!((t, i, j; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the arguments i, j as a site indices, instead of a positions. Here i is the destination (row) and j the source (column) site. In fact, the type of i and j is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nExamples\n\njulia> model = hopping(1); peierls = @hopping!((t, r, dr; A = r -> SA[0,0]) -> t * cis(-dr' * A(r)))\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : spatial\n Parameters : [:A]\n\njulia> LP.honeycomb() |> hamiltonian(model) |> supercell(10) |> hamiltonian(peierls)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 5\n Harmonic size : 200 × 200\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 0\n Hoppings : 600\n Coordination : 3.0\n Parameters : [:A]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@onsite","page":"API","title":"Quantica.@onsite","text":"@onsite((; params...) -> o(; params...); sites...)\n@onsite((r; params...) -> o(r; params...); sites...)\n\nBuild a ParametricModel representing a uniform or a position-dependent onsite potential, respectively, on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The onsite potential o can be a Number (for single-orbital sites), a UniformScaling (e.g. 2I) or an AbstractMatrix (use SMatrix for performance) of dimensions matching the number of orbitals in the selected sites. Parametric models may be applied to a lattice lat to produce a ParametricHamiltonian with hamiltonian(lat, model; ...), see hamiltonian. Position dependent models are forced to preserve the periodicity of the lattice.\n\nThe difference between regular and parametric tight-binding models (see onsite and hopping) is that parametric models may depend on arbitrary parameters, specified by the params keyword arguments. These are inherited by h::ParametricHamiltonian, which can then be evaluated very efficiently for different parameter values by callling h(; params...), to obtain a regular Hamiltonian without reconstructing it from scratch.\n\n@onsite((ω; params...) -> Σᵢᵢ(ω; params...); sites...)\n@onsite((ω, r; params...) -> Σᵢᵢ(ω, r; params...); sites...)\n\nSpecial form of a parametric onsite potential meant to model a self-energy (see attach).\n\n@onsite((i; params...) --> ...; sites...)\n@onsite((ω, i; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nModel algebra\n\nParametric models can be combined using +, - and *, or conjugated with ', e.g. @onsite((; o=1) -> o) - 2 * hopping(1)'. The combined parametric models can share parameters.\n\nExamples\n\njulia> model = @onsite((r; dμ = 0) -> (r[1] + dμ) * I; sublats = :A) + @onsite((; dμ = 0) -> - dμ * I; sublats = :B)\nParametricModel: model with 2 terms\n ParametricOnsiteTerm{ParametricFunction{1}}\n Region : any\n Sublattices : A\n Cells : any\n Coefficient : 1\n Argument type : spatial\n Parameters : [:dμ]\n ParametricOnsiteTerm{ParametricFunction{0}}\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1\n Argument type : spatial\n Parameters : [:dμ]\n\njulia> LP.honeycomb() |> supercell(2) |> hamiltonian(model, orbitals = 2)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 8 × 8\n Orbitals : [2, 2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 8\n Hoppings : 0\n Coordination : 0.0\n Parameters : [:dμ]\n\nSee also\n\n`onsite`, `hopping`, `@hopping`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"api/#Quantica.@onsite!","page":"API","title":"Quantica.@onsite!","text":"@onsite!((o; params...) -> o´(o; params...); sites...)\n@onsite!((o, r; params...) -> o´(o, r; params...); sites...)\n\nBuild a uniform or position-dependent onsite term modifier, respectively, acting on sites selected by siteselector(; sites...) (see siteselector for details).\n\nSite positions are r::SVector{E}, where E is the embedding dimension of the lattice. The original onsite potential is o, and the modified potential is o´, which is a function of o and possibly r. It may optionally also depend on parameters, enconded in params.\n\nModifiers are meant to be applied to an h:AbstractHamiltonian to obtain a ParametricHamiltonian (with hamiltonian(h, modifiers...) or hamiltonian(lat, model, modifiers...), see hamiltonian). Modifiers will affect only pre-existing model terms. In particular, if no onsite model has been applied to a specific site, its onsite potential will be zero, and will not be modified by any @onsite! modifier. Conversely, if an onsite model has been applied, @onsite! may modify the onsite potential even if it is zero. The same applies to @hopping!.\n\n@onsite((o, i; params...) --> ...; sites...)\n\nThe --> syntax allows to treat the argument i as a site index, instead of a position. In fact, the type of i is CellSitePos, so they can be used to index OrbitalSliceArrays (see doctrings for details). The functions pos(i), cell(i) and ind(i) yield the position, cell and site index of the site. This syntax is useful to implement models that depend on observables (in the form of OrbitalSliceArrays), like in self-consistent mean field calculations.\n\nExamples\n\njulia> model = onsite(0); disorder = @onsite!((o; W = 0) -> o + W * rand())\nOnsiteModifier{ParametricFunction{1}}:\n Region : any\n Sublattices : any\n Cells : any\n Argument type : spatial\n Parameters : [:W]\n\njulia> LP.honeycomb() |> hamiltonian(model) |> supercell(10) |> hamiltonian(disorder)\nParametricHamiltonian{Float64,2,2}: Parametric Hamiltonian on a 2D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 200 × 200\n Orbitals : [1, 1]\n Element type : scalar (ComplexF64)\n Onsites : 200\n Hoppings : 0\n Coordination : 0.0\n Parameters : [:W]\n\nSee also\n\n`onsite`, `hopping`, `@onsite`, `@hopping`, `@hopping!`, `hamiltonian`, `OrbitalSliceArray`\n\n\n\n\n\n","category":"macro"},{"location":"tutorial/observables/#Observables","page":"Observables","title":"Observables","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We are almost at our destination now. We have defined a Lattice, a Model for our system, we applied the Model to the Lattice to obtain a Hamiltonian or a ParametricHamiltonian, and finally, after possibly attaching some contacts to outside reservoirs and specifying a GreenSolver, we obtained a GreenFunction. It is now time to use the GreenFunction to obtain some observables of interest.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Currently, we have the following observables built into Quantica.jl (with more to come in the future)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"ldos: computes the local density of states at specific energy and sites\ndensitymatrix: computes the density matrix at thermal equilibrium on specific sites.\ncurrent: computes the local current density along specific directions, and at specific energy and sites\ntransmission: computes the total transmission between contacts\nconductance: computes the differential conductance dIᵢ/dVⱼ between contacts i and j\njosephson: computes the supercurrent and the current-phase relation through a given contact in a superconducting system","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"See the corresponding docstrings for full usage instructions. Here we will present some basic examples","category":"page"},{"location":"tutorial/observables/#Local-density-of-states-(LDOS)","page":"Observables","title":"Local density of states (LDOS)","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Let us compute the LDOS in a cavity like in the previous section. Instead of computing the Green function between a contact to an arbitrary point, we can construct an object d = ldos(g(ω)) without any contacts. By using a small imaginary part in ω, we broaden the discrete spectrum, and obtain a finite LDOS. Then, we can pass d directly as a site shader to qplot","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> h = LP.square() |> onsite(4) - hopping(1) |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1]))));\n\njulia> g = h |> greenfunction;\n\njulia> d = ldos(g(0.1 + 0.001im))\nLocalSpectralDensitySolution{Float64} : local density of states at fixed energy and arbitrary location\n kernel : LinearAlgebra.UniformScaling{Bool}(true)\n\njulia> qplot(h, hide = :hops, sitecolor = d, siteradius = d, minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"LDOS\"","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that d[sites...] produces a vector with the LDOS at sites defined by siteselector(; sites...) (d[] is the ldos over all sites). We can also define a kernel to be traced over orbitals to obtain the spectral density of site-local observables (see diagonal slicing in the preceding section).","category":"page"},{"location":"tutorial/observables/#Density-matrix","page":"Observables","title":"Density matrix","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We can also compute the convolution of the density of states with the Fermi distribution f(ω)=1/(exp((ω-μ)/kBT) + 1), which yields the density matrix in thermal equilibrium, at a given temperature kBT and chemical potential μ. This is computed with ρ = densitymatrix(gs, (ωmin, ωmax)). Here gs = g[sites...] is a GreenSlice, and (ωmin, ωmax) are integration bounds (they should span the full bandwidth of the system). Then, ρ(µ, kBT = 0; params...) will yield a matrix over the selected sites for a set of model params.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> ρ = densitymatrix(g[region = RP.circle(1)], (-0.1, 8.1))\nDensityMatrix{DensityMatrixIntegratorSolver}: density matrix on specified sites\n\njulia> @time ρ(4)\n 4.594645 seconds (111.82 k allocations: 4.890 GiB, 2.81% gc time, 0.86% compilation time)\n5×5 OrbitalSliceMatrix{ComplexF64,Array}:\n 0.5+0.0im -7.35075e-10+3.40256e-15im 0.204478+4.46023e-14im -7.35077e-10-1.13342e-15im -5.70426e-10-2.22213e-15im\n -7.35075e-10-3.40256e-15im 0.5+0.0im 0.200693-4.46528e-14im -5.70431e-10+3.53853e-15im -7.35092e-10-4.07992e-16im\n 0.204478-4.46023e-14im 0.200693+4.46528e-14im 0.5+0.0im 0.200693+6.7793e-14im 0.204779-6.78156e-14im\n -7.35077e-10+1.13342e-15im -5.70431e-10-3.53853e-15im 0.200693-6.7793e-14im 0.5+0.0im -7.351e-10+2.04708e-15im\n -5.70426e-10+2.22213e-15im -7.35092e-10+4.07992e-16im 0.204779+6.78156e-14im -7.351e-10-2.04708e-15im 0.5+0.0im","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that the diagonal is 0.5, indicating half-filling.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The default algorithm used here is slow, as it relies on numerical integration in the complex plane. Some GreenSolvers have more efficient implementations. If they exist, they can be accessed by omitting the (ωmin, ωmax) argument. For example, using GS.Spectrum:","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> @time g = h |> greenfunction(GS.Spectrum());\n 18.249136 seconds (75 allocations: 1.567 GiB, 0.67% gc time)\n\njulia> ρ = densitymatrix(g[region = RP.circle(1)])\nDensityMatrix{DensityMatrixSpectrumSolver}: density matrix on specified sites\n\njulia> @time ρ(4) # second-run timing\n 0.029662 seconds (7 allocations: 688 bytes)\n5×5 OrbitalSliceMatrix{ComplexF64,Array}:\n 0.5+0.0im -6.6187e-16+0.0im 0.204478+0.0im 2.49658e-15+0.0im -2.6846e-16+0.0im\n -6.6187e-16+0.0im 0.5+0.0im 0.200693+0.0im -2.01174e-15+0.0im 1.2853e-15+0.0im\n 0.204478+0.0im 0.200693+0.0im 0.5+0.0im 0.200693+0.0im 0.204779+0.0im\n 2.49658e-15+0.0im -2.01174e-15+0.0im 0.200693+0.0im 0.5+0.0im 1.58804e-15+0.0im\n -2.6846e-16+0.0im 1.2853e-15+0.0im 0.204779+0.0im 1.58804e-15+0.0im 0.5+0.0im\n","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note, however, that the computation of g is much slower in this case, due to the need of a full diagonalization. A better algorithm choice in this case is GS.KPM. It requires, however, that we define the region for the density matrix beforehand, as a nothing contact.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> @time g = h |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 10000, bandrange = (0,8)));\nComputing moments: 100%|███████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01\n 1.360412 seconds (51.17 k allocations: 11.710 MiB)\n\njulia> ρ = densitymatrix(g[1])\nDensityMatrix{DensityMatrixKPMSolver}: density matrix on specified sites\n\njulia> @time ρ(4)\n 0.004024 seconds (3 allocations: 688 bytes)\n5×5 OrbitalSliceMatrix{ComplexF64,Array}:\n 0.5+0.0im 2.15097e-17+0.0im 0.20456+0.0im 2.15097e-17+0.0im 3.9251e-17+0.0im\n 2.15097e-17+0.0im 0.5+0.0im 0.200631+0.0im 1.05873e-16+0.0im 1.70531e-18+0.0im\n 0.20456+0.0im 0.200631+0.0im 0.5+0.0im 0.200631+0.0im 0.20482+0.0im\n 2.15097e-17+0.0im 1.05873e-16+0.0im 0.200631+0.0im 0.5+0.0im 1.70531e-18+0.0im\n 3.9251e-17+0.0im 1.70531e-18+0.0im 0.20482+0.0im 1.70531e-18+0.0im 0.5+0.0im","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"note: Alternative integration paths\nThe integration algorithm allows many different integration paths that can be adjusted to each problem, see the Paths docstring. Another versatile choice is Paths.radial(ωrate, ϕ). This one is called with ϕ = π/4 when doing ρ = densitymatrix(gs::GreenSlice, ωrate::Number). In the example above this is slightly faster than the (ωmin, ωmax) choice, which resorts to Paths.sawtooth(ωmin, ωmax).","category":"page"},{"location":"tutorial/observables/#Current","page":"Observables","title":"Current","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"A similar computation can be done to obtain the current density, using J = current(g(ω), direction = missing). This time J[sᵢ, sⱼ] yields a sparse matrix of current densities along a given direction for each hopping (or the current norm if direction = missing). Passing J as a hopping shader yields the equilibrium current in a system. In the above example we can add a magnetic flux to make this current finite","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> h = LP.square() |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1])))) |> onsite(4) - @hopping((r, dr; B = 0.1) -> cis(B * dr[1] * r[2]));\n\njulia> g = h |> greenfunction;\n\njulia> J = current(g(0.1; B = 0.01))\nCurrentDensitySolution{Float64} : current density at a fixed energy and arbitrary location\n charge : LinearAlgebra.UniformScaling{Int64}(-1)\n direction : missing\n\njulia> qplot(h, siteradius = 0.08, sitecolor = :black, siteoutline = 0, hopradius = J, hopcolor = J, minmaxhopradius = (0, 2), hopcolormap = :balance, hopdarken = 0)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Current","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"note: Remember to construct supercell before applying position-dependent fields\nNote that we built the supercell before applying the model with the magnetic flux. Not doing so would make the gauge field be repeated in each unit cell when expanding the supercell. This was mentioned in the section on Hamiltonians, and is a common mistake when modeling systems with position dependent fields.","category":"page"},{"location":"tutorial/observables/#Transmission","page":"Observables","title":"Transmission","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The transmission Tᵢⱼ from contact j to contact i can be computed using transmission. This function accepts a GreenSlice between the contact. Let us recover the four-terminal setup of the preceding section, but let's make it bigger this time","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> hcentral = LP.square() |> hopping(-1) |> supercell(region = RP.circle(100) | RP.rectangle((202, 50)) | RP.rectangle((50, 202)))\n\njulia> glead = LP.square() |> hopping(-1) |> supercell((1, 0), region = r -> abs(r[2]) <= 50/2) |> greenfunction(GS.Schur(boundary = 0));\n\njulia> Rot = r -> SA[0 -1; 1 0] * r; # 90º rotation function\n\njulia> g = hcentral |>\n attach(glead, region = r -> r[1] == 101) |>\n attach(glead, region = r -> r[1] == -101, reverse = true) |>\n attach(glead, region = r -> r[2] == 101, transform = Rot) |>\n attach(glead, region = r -> r[2] == -101, reverse = true, transform = Rot) |>\n greenfunction;\n\njulia> gx1 = abs2.(g(-3.96)[siteselector(), 1]);\n\njulia> qplot(hcentral, hide = :hops, siteoutline = 1, sitecolor = gx1, siteradius = gx1, minmaxsiteradius = (0, 2), sitecolormap = :balance)","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Green","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"tip: Matrix and vector shaders\nIn the above example gx1 is a matrix with one row per orbital in hcentral. The color and radii of each site is obtained from the sum of each row. If gx1 were a vector, the color/radius of site i would be taken as gx1[i]. See plotlattice for more details and other shader types.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"It's apparent from the plot that the transmission from right to left (T₂₁ here) at this energy of 0.04 is larger than from right to top (T₃₁). Is this true in general? Let us compute the two transmissions as a function of energy. To show the progress of the calculation we can use a monitor package, such as ProgressMeter","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> using ProgressMeter\n\njulia> T₂₁ = transmission(g[2,1]); T₃₁ = transmission(g[3,1]); ωs = subdiv(-4, 4, 201);\n\njulia> T₂₁ω = @showprogress [T₂₁(ω) for ω in ωs]; T₃₁ω = @showprogress [T₃₁(ω) for ω in ωs];\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:02\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:00\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"ω/t\", ylabel = \"T(ω)\"); lines!(a, ωs, T₂₁ω, label = L\"T_{2,1}\"); lines!(a, ωs, T₃₁ω, label = L\"T_{3,1}\"); axislegend(\"Transmission\", position = :lt); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Total","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"So we indeed find that the 90-degree transmission T₃₁ is indeed larger than the forward transmission T₂₁ for all energies. The rapid oscillations are due to mesoscopic fluctuations.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"note: Total transmission vs transmission probability\nNote that transmission gives the total transmission, which is the sum of the transmission probability from each orbital in the source contact to any other orbital in the drain contact. As such it is not normalized to 1, but to the number of source orbitals. It also gives the local conductance from a given contact in units of e^2h according to the Landauer formula, G_j = e^2h sum_i T_ij(eV).","category":"page"},{"location":"tutorial/observables/#Conductance","page":"Observables","title":"Conductance","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Local and non-local differential conductance G_ij = dI_idV_j can be computed with G = conductance(g[i,j]). Calling G(ω) returns the conductance at bias eV = omega in units of e^2h. Let's look at the local differential conductance into the right contact in the previous example","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> G₁₁ = conductance(g[1,1])\nConductance{Float64}: Zero-temperature conductance dIᵢ/dVⱼ from contacts i,j, in units of e^2/h\n Current contact : 1\n Bias contact : 1\n\njulia> ωs = subdiv(-4, 4, 201); Gω = @showprogress [G₁₁(ω) for ω in ωs];\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:01\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"eV/t\", ylabel = \"G [e²/h]\"); lines!(a, ωs, Gω); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Local","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"warning: Sign of non-local conductance\nIf you compute a non-local conductance such as conductance(g[2,1])(ω) in this example you will note it is negative. This is actually expected. It means that the current flowing into the system through the right contact when you increase the bias in a different contact is negative, because the current is actually flowing out into the right reservoir.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The conductance can also be computed for hybrid (normal-superconducting) systems. To do so, one first needs to write the model in the Nambu representation, i.e. with particle and hole orbitals on each site (first particles, then holes). In the above examples amounts to switching hopping(-1) to hamiltonian(onsite(Δ*σx) - hopping(σz), orbitals = 2), with σx = SA[0 1; 1 0], σz = SA[1 0; 0 -1] and Δ the pairing amplitude. Then we must specify G₁₁ = conductance(g[1,1], nambu = true) to take into account Andreev reflections. The above example with left, bottom and top leads superconducting (with Δ=0.3) yields the following conductance G₁₁ in the right (normal) lead (we leave the implementation as an exercise for the reader).","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Local","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that within the gap Andreev reflection leads to an enhancement of conductance, since the contacts are transparent","category":"page"},{"location":"tutorial/observables/#Josephson","page":"Observables","title":"Josephson","text":"","category":"section"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"The above example showcases normal-superconductor (NS) conductance, which is a Fermi-surface process in response to an electric bias on the normal contacts. In contrast, supercorconductor-superconductor junctions, also known as Josephson junctions, can exhibit supercurrents carried by the full Fermi sea even without a bias. Usually, this supercurrent flows in response to a phase bias between the superconductors, where by phase we mean the complex phase of the Δ order parameter.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"We can compute the supercurrent or the full current-phase relation of a Josephson junction with the command josephson(gs::GreenSlice, ωmax), where gs = g[contact_id] and ωmax is the full bandwidth of the system (i.e. the maximum energy, in absolute value, spanned by the Fermi sea). This latter quantity can be an estimate or even an upper bound, as it is just used to know up to which energy we should integrate the supercurrent. Let us see an example.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> σz = SA[1 0; 0 -1];\n\njulia> central_region = RP.circle(50) & !RP.circle(40) | RP.rectangle((4, 10), (-50, 0)) | RP.rectangle((4, 10), (50, 0));\n\njulia> h = LP.square() |> hamiltonian(hopping(-σz), orbitals = 2) |> supercell(region = central_region)\n\njulia> Σ(ω, Δ) = SA[-ω Δ; conj(Δ) -ω]/sqrt(1-abs2(Δ))\n\njulia> g = h |>\n attach(@onsite((ω; Δ = 0.2) -> Σ(ω, Δ)); region = r -> r[1] < -51) |>\n attach(@onsite((ω; Δ = 0.2, phase = 0) -> Σ(ω, Δ*cis(phase))); region = r -> r[1] > 51) |>\n greenfunction\nGreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}\n Solver : AppliedSparseLUGreenSolver\n Contacts : 2\n Contact solvers : (SelfEnergyModelSolver, SelfEnergyModelSolver)\n Contact sizes : (11, 11)\n Hamiltonian{Float64,2,0}: Hamiltonian on a 0D Lattice in 2D space\n Bloch harmonics : 1\n Harmonic size : 2884 × 2884\n Orbitals : [2]\n Element type : 2 × 2 blocks (ComplexF64)\n Onsites : 0\n Hoppings : 10800\n Coordination : 3.7448\n\njulia> J = josephson(g[1], 4.1)\nJosephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact\n\njulia> qplot(g, children = (; sitecolor = :blue))","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Josephson","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"In this case we have chosen to introduce the superconducting leads with a model self-energy, corresponding to a BCS bulk, but any other self-energy form could be used. We have introduced the phase difference (phase) as a model parameter. We can now evaluate the zero-temperature Josephson current simply with","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> J(phase = 0)\n1.992660837638158e-12\n\njulia> J(phase = 0.2)\n0.0046175971391935605","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"Note that finite temperatures can be taken using the kBT keyword argument for josephson, see docstring for details.","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"One is often interested in the critical current, which is the maximum of the Josephson current over all phase differences. Quantica.jl can compute the integral over a collection of phase differences simultaneously, which is more efficient that computing them one by one. This is done with","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"julia> φs = subdiv(0, pi, 11); J = josephson(g[1], 4.1; phases = φs)\nJosephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact\n\njulia> Iφ = J()\n11-element Vector{Float64}:\n -6.361223111882911e-13\n 0.007231421776215144\n 0.01424285518831463\n 0.020818707606469377\n 0.026752065101976884\n 0.031847203846513975\n 0.035913141096514584\n 0.038718955102068034\n 0.03976244268586444\n 0.036800967573567184\n -1.437196514806921e-12\n\njulia> f = Figure(); a = Axis(f[1,1], xlabel = \"φ\", ylabel = \"I [e/h]\"); lines!(a, φs, Iφ); scatter!(a, φs, Iφ); f","category":"page"},{"location":"tutorial/observables/","page":"Observables","title":"Observables","text":"\"Josephson","category":"page"},{"location":"examples/#Examples","page":"Examples","title":"Examples","text":"","category":"section"},{"location":"tutorial/models/#Models","page":"Models","title":"Models","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We now will show how to build a generic single-particle tight-binding model, with generic Hamiltonian","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"H = sum_ialpha jbeta c_ialpha^dagger V_alphabeta(r_i r_j)c_jalpha","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Here, α,β are orbital indices in each site, i,j are site indices, and rᵢ, rⱼ are site positions. In Quantica.jl we would write the above model as","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = onsite(r -> V(r, r)) + hopping((r, dr) -> V(r-dr/2, r+dr/2))\nTightbindingModel: model with 2 terms\n OnsiteTerm{Function}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n HoppingTerm{Function}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where V(rᵢ, rⱼ) is a function that returns a matrix (ideally an SMatrix) V_alphabeta(r_i r_j) of the required orbital dimensionality.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Note that when writing models we distinguish between onsite (rᵢ=rⱼ) and hopping (rᵢ≠rⱼ) terms. For the former, r is the site position. For the latter we use a bond-center and bond-distance (r, dr) parametrization of V, so that r₁, r₂ = r ∓ dr/2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"If the onsite and hopping amplitudes do not depend on position, we can simply use constants","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = onsite(1) - 2*hopping(1)\nTightbindingModel: model with 2 terms\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 1\n HoppingTerm{Int64}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : -2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: Model term algebra\nNote that we can combine model terms as in the above example by summing and subtracting them, and using constant coefficients.","category":"page"},{"location":"tutorial/models/#HopSelectors","page":"Models","title":"HopSelectors","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"By default onsite terms apply to any site in a Lattice, and hopping terms apply to any pair of sites within nearest-neighbor distance (see the Hopping range: Neighbors(1) above).","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We can change this default by specifying a SiteSelector or HopSelector for each term. SiteSelectors where already introduced to create LatticeSlices. HopSelectors are very similar, but support slightly different keywords:","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"region: to restrict according to bond center r and bond vector dr\nsublats: to restrict source and target sublattices\ndcells: to restrict the distance in cell index\nrange: to restrict the distance in real space","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"As an example, a HopSelector that selects any two sites at a distance between 1.0 and the second-nearest neighbor distance, with the first belonging to sublattice :B and the second to sublattice :A, and their bond center inside a unit circle","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> hs = hopselector(range = (1.0, neighbors(2)), sublats = :B => :A, region = (r, dr) -> norm(r) < 1)\nHopSelector: a rule that defines a finite collection of hops between sites in a lattice\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : false","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"We can now use this HopSelector to restrict the hoppings in a model, just as SiteSelectors can be used to restrict onsite terms","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model = plusadjoint(hopping(1, hs)) - 2*onsite(1, sublats = :B)\nTightbindingModel: model with 3 terms\n HoppingTerm{Int64}:\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : false\n Coefficient : 1\n HoppingTerm{Int64}:\n Region : Function\n Sublattice pairs : :B => :A\n Cell distances : any\n Hopping range : (1.0, Neighbors(2))\n Reverse hops : true\n Coefficient : 1\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Note that we can pass the Selector itself as a second argument to hopping and onsite, or alternatively use selector keywords directly as in the onsite above.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: plusadjoint function\nThe convenience function plusadjoint(term) = term + term' adds the Hermitian conjugate of its argument (term'), equivalent to the + h.c. notation often used in the literature.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"note: Index-agnostic modeling\nThe Quantica.jl approach to defining tight-binding models does not rely explicitly on site indices (i,j above), since these are arbitrary, and may even be beyond the control of the user (for example after using supercell). Instead, we rely on physical properties of sites, such as position, distance or sublattice.","category":"page"},{"location":"tutorial/models/#Parametric-Models","page":"Models","title":"Parametric Models","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"The models introduced above are non-parametric, in the sense that they encode fixed, numerical Hamiltonian matrix elements. In many problems, it is commonplace to have models that depend on a number of free parameters that will need to be adjusted during a calculation. For example, one may need to compute the phase diagram of a system as a function of a spin-orbit coupling or an applied magnetic field. For these cases, we have ParametricModels.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"Parametric models are defined with","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"@onsite((; params...) -> ...; sites...)\n@onsite((r; params...) -> ...; sites...)\n@hopping((; params...) -> ...; hops...)\n@hopping((r, dr; params...) -> ...; hops...)","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where the params keyword arguments define the free parameters, together with (optional) default values. Here is an example of a hopping model with a Peierls phase in the symmetric gauge, with the magnetic field Bz and the zero-field hopping t as free parameters","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model_perierls = @hopping((r, dr; Bz = 0, t = 1) -> t * cis(-im * Bz/2 * SA[-r[2], r[1], 0]' * dr))\nParametricModel: model with 1 term\n ParametricHoppingTerm{ParametricFunction{2}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : 1\n Argument type : spatial\n Parameters : [:Bz, :t]","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"One can linearly combine parametric and non-parametric models freely, omit parameter default values, and use any of the functional argument forms described for onsite and hopping (although not the constant argument form):","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model´ = 2 * (onsite(1) - 2 * @hopping((; t) -> t))\nParametricModel: model with 2 terms\n ParametricHoppingTerm{ParametricFunction{0}}\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\n Coefficient : -4\n Argument type : spatial\n Parameters : [:t]\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 2","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"tip: Non-spatial parametric models with -->\nThe -> in the above parametric models @onsite and @hopping, but also in the modifiers below, can be changed to -->. This indicates that the function arguments are no longer treated as site or link positions r and dr, but as objects i, j representing destination and source sites. This allows to address sites directly instead of through their spatial location. See the Mean Field section for further details.","category":"page"},{"location":"tutorial/models/#Modifiers","page":"Models","title":"Modifiers","text":"","category":"section"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"There is a third model-related functionality known as OnsiteModifiers and HoppingModifiers. Given a model that defines a set of onsite and hopping amplitudes on a subset of sites and hops, one can define a parameter-dependent modification of a subset of said amplitudes. This is a useful way to introduce a new parameter dependence on an already defined model. Modifiers are built with","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"@onsite!((o; params...) -> new_onsite; sites...)\n@onsite!((o, r; params...) -> new_onsite; sites...)\n@hopping((t; params...) -> new_hopping; hops...)\n@hopping((t, r, dr; params...) -> new_hopping; hops...)","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"where the first argument o and t is the unmodified value of the onsite or hopping amplitude, respectively. Here sites and hops are once more keyword arguments to restrict the modification with a SiteSelector or HopSelector.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"For example, the following HoppingModifier inserts a Peierls phase on all the hopping in a given model","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"julia> model_perierls! = @hopping!((t, r, dr; B = 0) -> t * cis(-Bz/2 * SA[-r[2], r[1], 0]' * dr))\nHoppingModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Inf\n Reverse hops : false\n Argument type : spatial\n Parameters : [:B]","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"The difference with model_perierls is that model_perierls! will never add any new hoppings. It will only modify previously existing hoppings in a model. Modifiers are not models themselves, and cannot be summed to other models. They are instead meant to be applied sequentially after applying a model.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"In the next section we show how models and modifiers can be used in practice to construct Hamiltonians.","category":"page"},{"location":"tutorial/models/","page":"Models","title":"Models","text":"note: Mind the `;`\nWhile syntax like onsite(2, sublats = :B) and onsite(2; sublats = :B) are equivalent in Julia, due to the way keyword arguments are parsed, the same is not true for macro calls like @onsite, @onsite!, @hopping and @hopping!. These macros just emulate the function call syntax. But to work you must currently always use the ; separator for keywords. Hence, something like @onsite((; p) -> p; sublats = :B) works, but @onsite((; p) -> p, sublats = :B) does not.","category":"page"},{"location":"tutorial/bandstructures/#Bandstructures","page":"Bandstructures","title":"Bandstructures","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The eigenpairs (eigenvalues and eigenvectors) of a Hamiltonian or ParametricHamiltonian at given Bloch phases ϕᵢ can be obtained with spectrum:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.honeycomb() |> hopping(1); ϕᵢ = (0, π);\n\njulia> eᵢ, ψᵢ = spectrum(h, ϕᵢ; solver = EigenSolvers.LinearAlgebra())\nSpectrum{Float64,ComplexF64} :\nEnergies:\n2-element Vector{ComplexF64}:\n -1.0 + 0.0im\n 1.0 + 0.0im\nStates:\n2×2 Matrix{ComplexF64}:\n 0.707107-8.65956e-17im 0.707107-8.65956e-17im\n -0.707107+0.0im 0.707107+0.0im","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The above destructuring syntax assigns eigenvalues and eigenvectors to eᵢ and ψᵢ, respectively. The available eigensolvers and their options can be checked in the EigenSolvers docstrings. They are supported through the extension mechanism in Julia, so they require additional libraries to be loaded first, such as using Arpack or using ArnoldiMethod.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"warning: Arpack solver is not thread-safe\nEigenSolvers.Arpack relies on a Fortran library that is not currently thread-safe. If you launch Julia with multiple threads, they will not be used with this specific solver. Otherwise Arpack would segfault.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"We define a \"bandstructure\" of an h::AbstractHamiltonian as a linear interpolation of its eigenpairs over a portion of the Brillouin zone, which is discretized with a base mesh of ϕᵢ values. At each ϕᵢ of the base mesh, the Bloch matrix h(ϕᵢ) is diagonalized with spectrum. The adjacent eigenpairs eⱼ(ϕᵢ), ψⱼ(ϕᵢ) are then connected (\"stitched\") together into a number of band meshes with vertices (ϕᵢ..., eⱼ(ϕᵢ)) by maximizing the overlap of adjacent ψⱼ(ϕᵢ) (since the bands should be continuuous). Degenerate eigenpairs are collected into a single node of the band mesh.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The bandstructure of an h::AbstractHamiltonian is computed using bands:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> ϕ₁points = ϕ₂points = range(0, 2π, length = 19);\n\njulia> b = bands(h, ϕ₁points, ϕ₂points)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 720\n Edges : 2016\n Simplices : 1296","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The first argument is the AbstractHamiltonian. Here it is defined on an L=2 dimensional lattice. The subsequent arguments are collections of Bloch phases on each of the L axes of the Brillouin zone, whose direct product ϕ₁points ⊗ ϕ₂points defines our base mesh of ϕᵢ points. Here it is a uniform 19×19 grid. We can once more use qplot to visualize the bandstructure, or more precisely the band meshes:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> using GLMakie; qplot(b)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The dots on the bands are the band mesh vertices (ϕᵢ..., eⱼ(ϕᵢ)). They can be omitted with the qplot keyword hide = :nodes (or hide = :vertices, both are equivalent).","category":"page"},{"location":"tutorial/bandstructures/#Band-defects","page":"Bandstructures","title":"Band defects","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"Note that the uniform grid contains the Dirac points. This is the reason for the number 19 of Bloch phases used above. Note also that it is identified as a point in the bands with degeneracy = 2 (the rest have degeneracy = 1). As mentioned, the points on the bands are connected based on eigenstate overlaps between adjacent ϕᵢs. This interpolation algorithm can deal with subspace degeneracies, as here. However, Dirac points (and Diabolical Points in general) must belong to the mesh for the method to work. If the number of points is reduced to 18 per axis, the Dirac points become unavoidable band dislocations, that appear as missing simplices in the bands:","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: Advanced: band defects and patching\nIf a Dirac point or other type of band dislocation point happens to not belong to the sampling grid, it can be added with the bands keyword defects. Then, it can be reconnected with the rest of the band by increasing the patches::Integer keyword (see bands docstring for details). This \"band repair\" functionality is experimental, and should only be necessary in some cases with Diabolical Points.","category":"page"},{"location":"tutorial/bandstructures/#Coordinate-mapping-and-band-linecuts","page":"Bandstructures","title":"Coordinate mapping and band linecuts","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The direct product of the ϕᵢpoints above define a rectangular mesh over which we want to compute the bandstructure. By default, this mesh is taken as a discretization of Bloch phases, so h(ϕᵢ) is diagonalized at each point of the base mesh. We might want, however, a different relation between the mesh and the parameters passed to h, for example if we wish to use wavevectors k instead of Bloch phases ϕᵢ = k⋅Aᵢ for the mesh. This is achieved with the mapping keyword, which accepts a function mapping = (mesh_points...) -> bloch_phases,","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.honeycomb() |> hopping(2); k₁points = range(-2π, 2π, length = 51); k₂points = range(-2π, 2π, length = 51);\n\njulia> Kpoints = [SA[cos(θ) -sin(θ); sin(θ) cos(θ)] * SA[4π/3,0] for θ in range(0, 5*2π/6, length = 6)];\n\njulia> ϕ(k...) = SA[k...]' * bravais_matrix(h)\nϕ (generic function with 1 method)\n\njulia> b = bands(h, k₁points, k₂points; mapping = ϕ, defects = Kpoints, patches = 20);\n\njulia> using GLMakie; qplot(b, hide = (:nodes, :wireframe), color = :orange)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"To compute a bandstructure linecut along a polygonal line in the Brillouin zone, we could once more use the mapping functionality, mapping a set of points xᵢ::Real in the mesh to Bloch phases ϕᵢ that defines the nodes of the polygonal path, and interpolating linearly between them. To avoid having to construct this mapping ourselves, mapping accepts a second type of input for this specific usecase, mapping = xᵢ => ϕᵢ. Here, ϕᵢ can be a collection of Tuples, SVector{L}, or even Symbols denoting common names for high-symmetry points in the Brillouin zone, such as :Γ, :K, :K´, :M, :X, :Y, and :Z. The following gives a Γ-K-M-Γ linecut for the bands above, where the (Γ, K, M, Γ) points lie at x = (0, 2, 3, 4), respectively, with 10 subdivisions in each segment,","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> b = bands(h, subdiv((0, 2, 3, 4), 10); mapping = (0, 2, 3, 4) => (:Γ, :K, :M, :Γ));\n\njulia> qplot(b, axis = (; xticks = ([0, 2, 3, 4], [\"Γ\", \"K\", \"M\", \"Γ\"]), ylabel = \"ϵ\"))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Graphene","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: subdiv\nThe subdiv function is a convenience function provided by Quantica.jl that generalizes range (see the corresponding docstring for comprehensive details). It is useful to create collections of numbers as subdivisions of intervals, as in the example above. In its simplest form subdiv(min, max, npoints) is is equivalent to range(min, max, npoints).","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The mapping keyword understand a third syntax that can be used to map a mesh to the space of Bloch phases and parameters of a ParametricHamiltonian. To this end we use mapping = (mesh_points...) -> ftuple(bloch_phases...; params...). The ftuple function creates a FrankenTuple, which is a hybrid between a Tuple and a NamedTuple. For example, in the following 1D SSH chain we can compute the bandstructure as a function of Bloch phase ϕ and hopping t´, and plot it using more customization options","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.linear() |> supercell(2) |> @hopping((r, dr; t = 1, t´ = 2) -> iseven(r[1]-1/2) ? t : t´);\n\njulia> b = bands(h, subdiv(0, 2π, 11), subdiv(0, 10, 11), mapping = (ϕ, y) -> ftuple(ϕ; t´ = y/5), patches = 20)\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 249\n Edges : 664\n Simplices : 416\n\njulia> qplot(b, nodedarken = 0.5, axis = (; aspect = (1,1,1), perspectiveness = 0.5, xlabel = \"ϕ\", ylabel = \"t´/t\", zlabel = \"ϵ\"), fancyaxis = false)","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"SSH","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"Note that since we didn't specify a value for t, it assumed its default t=1. In this case we needed to patch the defect at (ϕ, t´) = (π, 1) (topological transition) using the patches keyword to avoid a band dislocation.","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"If no parameters are specified or mapped, they take their default values. For example, this produces the 1D bandstructure of the SSH model for the default t = 1, t´ = 2 over the default 1D mesh (49 points, uniformly distributed in [-π, π])","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> qplot(bands(h))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"SSH","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"tip: Experimental `Quantica.gaps` and `Quantica.decay_lengths` for 1D Hamiltonians\nThe function Quantica.gaps(h, µ) can be used to efficiently calculate the gaps respect to chemical potential µ at local band minima, but only for 1D Hamiltonian's for the moment. Similarly Quantica.decay_lengths(h, µ; reverse = false) will yield the decay lengths of the evanescent modes of h at energy µ (towards the positive direction, unless reverse = true). Both functions are unexported and experimental.","category":"page"},{"location":"tutorial/bandstructures/#Band-indexing-and-slicing","page":"Bandstructures","title":"Band indexing and slicing","text":"","category":"section"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"The individual subbands in a given b::Bandstructure can be obtained with b[inds] with inds::Integer or inds::Vector, just as if b where a normal AbstractVector. The extracted subbands can also be plotted directly. The following example has 12 subbands, of which we extract and plot the first and last","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> h = LP.triangular() |> supercell(4) |> hopping(1) + onsite(r -> 4*rand());\n\njulia> b = bands(h, subdiv(0, 2π, 31), subdiv(0, 2π, 31))\nBandstructure{Float64,3,2}: 3D Bandstructure over a 2-dimensional parameter space of type Float64\n Subbands : 12\n Vertices : 15376\n Edges : 44152\n Simplices : 28696\n\njulia> qplot(b, hide = (:nodes, :wireframe))\n\njulia> qplot(b[[1, end]], hide = (:nodes, :wireframe))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Extracting","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"For a band in a 2D Brillouin zone, we can also obtain the intersection of a bandstructure with a plane of constant energy ϵ=2 using the syntax b[(:,:,2)]. A section at fixed Bloch phase ϕ₁=0 (or mesh coordinate x₁=0 if mapping was used), can be obtained with b[(0,:,:)]. This type of band slicing can be generalized to higher dimensional bandstructures, or to more than one constrain (e.g. energy and/or a subset of Bloch phases). As an example, this would be the Fermi surface of a nearest-neighbor cubic-lattice Hamiltonian at Fermi energy µ = 0.2t","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"julia> pts = subdiv(0, 2π, 41); b = LP.cubic() |> hopping(1) |> bands(pts, pts, pts)\nBandstructure{Float64,4,3}: 4D Bandstructure over a 3-dimensional parameter space of type Float64\n Subbands : 1\n Vertices : 68921\n Edges : 462520\n Simplices : 384000\n\njulia> qplot(b[(:, :, :, 0.2)], hide = (:nodes, :wireframe))","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"\"Fermi","category":"page"},{"location":"tutorial/bandstructures/","page":"Bandstructures","title":"Bandstructures","text":"warning: On simplex orientation of bandstructure slices\nThe above example showcases a current (cosmetic) limitation of the band slicing algorithm: it sometimes fails to align all faces of the resulting manifold to the same orientation. The dark and bright regions of the surface above reveals that approximately half of the faces in this case are facing inward and the rest outward.","category":"page"},{"location":"","page":"Home","title":"Home","text":"(Image: Quantica.jl logo)","category":"page"},{"location":"","page":"Home","title":"Home","text":"Quantica.jl is a Julia package for building generic tight-binding models and computing spectral and transport properties.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"julia> import Pkg; Pkg.add(\"Quantica\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"Quantica.jl requires Julia v1.9 or later. Some of its functionality, notably plotting, will become available only after using GLMakie, or some other plotting package from the Makie.jl family. Install GLMakie with","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> import Pkg; Pkg.add(\"GLMakie\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"Then, to begin using Quantica, just load it by doing","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using Quantica","category":"page"},{"location":"","page":"Home","title":"Home","text":"(and possibly also e.g. using GLMakie if you need to plot Quantica objects).","category":"page"},{"location":"#Asking-questions,-reporting-bugs","page":"Home","title":"Asking questions, reporting bugs","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"If you encounter problems, please read the tutorial and examples, your question is probably answered there. You can also check the docstring of each Quantica.jl function here or within the Julia REPL, by entering the function preceded by a ?, e.g. ?hamiltonian.","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you are still stuck, you may sometimes find me (@pablosanjose) at the Julia Slack or Julia Discourse.","category":"page"},{"location":"","page":"Home","title":"Home","text":"If you believe you found a bug in Quantica.jl, please don't hesitate to file a GitHub issue, preferably with detailed instructions to reproduce it. Pull requests with fixes are also welcome!","category":"page"}] } diff --git a/dev/tutorial/bandstructures/index.html b/dev/tutorial/bandstructures/index.html index 04493acc..8845aba6 100644 --- a/dev/tutorial/bandstructures/index.html +++ b/dev/tutorial/bandstructures/index.html @@ -55,4 +55,4 @@ Edges : 462520 Simplices : 384000 -julia> qplot(b[(:, :, :, 0.2)], hide = (:nodes, :wireframe))Fermi surface of a cubic crystal at `µ = 0.2t`
On simplex orientation of bandstructure slices

The above example showcases a current (cosmetic) limitation of the band slicing algorithm: it sometimes fails to align all faces of the resulting manifold to the same orientation. The dark and bright regions of the surface above reveals that approximately half of the faces in this case are facing inward and the rest outward.

+julia> qplot(b[(:, :, :, 0.2)], hide = (:nodes, :wireframe))Fermi surface of a cubic crystal at `µ = 0.2t`
On simplex orientation of bandstructure slices

The above example showcases a current (cosmetic) limitation of the band slicing algorithm: it sometimes fails to align all faces of the resulting manifold to the same orientation. The dark and bright regions of the surface above reveals that approximately half of the faces in this case are facing inward and the rest outward.

diff --git a/dev/tutorial/glossary/index.html b/dev/tutorial/glossary/index.html index 4d6fa2fd..51b348cb 100644 --- a/dev/tutorial/glossary/index.html +++ b/dev/tutorial/glossary/index.html @@ -1,2 +1,2 @@ -Glossary · Quantica.jl

Glossary

This is a summary of the type of objects you will be studying.

  • Sublat: a sublattice, representing a number of identical sites within the unit cell of a bounded or unbounded lattice. Each site has a position in an E-dimensional space (E is called the embedding dimension). All sites in a given Sublat will be able to hold the same number of orbitals, and they can be thought of as identical atoms. Each Sublat in a Lattice can be given a unique name, by default :A, :B, etc.

  • Lattice: a collection of Sublats plus a collection of L Bravais vectors that define the periodicity of the lattice. A bounded lattice has L=0, and no Bravais vectors. A Lattice with L > 0 can be understood as a periodic (unbounded) collection of unit cells, each containing a set of sites, each of which belongs to a different sublattice.

  • SiteSelector: a rule that defines a subset of sites in a Lattice (not necessarily restricted to a single unit cell)

  • HopSelector: a rule that defines a subset of site pairs in a Lattice (not necessarily restricted to the same unit cell)

  • LatticeSlice: a finite subset of sites in a Lattice, defined by their cell index (an L-dimensional integer vector, usually denoted by n or cell) and their site index within the unit cell (an integer). A LatticeSlice an be constructed by combining a Lattice and a (bounded) SiteSelector.

  • AbstractModel: either a TightBindingModel or a ParametricModel

    • TightBindingModel: a set of HoppingTerms and OnsiteTerms
      • OnsiteTerm: a rule that, applied to a single site, produces a scalar or a (square) matrix that represents the intra-site Hamiltonian elements (single or multi-orbital)
      • HoppingTerm: a rule that, applied to a pair of sites, produces a scalar or a matrix that represents the inter-site Hamiltonian elements (single or multi-orbital)
    • ParametricModel: a set of ParametricOnsiteTerms and ParametricHoppingTerms
      • ParametricOnsiteTerm: an OnsiteTerm that depends on a set of free parameters that can be adjusted, and that may or may not have a default value
      • ParametricHoppingTerm: a HoppingTerm that depends on parameters, like ParametricOnsiteTerm above
  • AbstractHamiltonian: either a Hamiltonian or a ParametricHamiltonian

    • Hamiltonian: a Lattice combined with a TightBindingModel.

      It also includes a specification of the number of orbitals in each Sublat in the Lattice. A Hamiltonian represents a tight-binding Hamiltonian sharing the same periodicity as the Lattice (it is translationally invariant under Bravais vector shifts).

    • ParametricHamiltonian: like the above, but using a ParametricModel, which makes it dependent on a set of free parameters that can be efficiently adjusted.

    An h::AbstractHamiltonian can be used to produce a Bloch matrix h(ϕ; params...) of the same size as the number of orbitals per unit cell, where ϕ = [ϕᵢ...] are Bloch phases and params are values for the free parameters, if any.

  • Spectrum: the set of eigenpairs (eigenvalues and corresponding eigenvectors) of a Bloch matrix. It can be computed with a number of EigenSolvers.

  • Bandstructure: a collection of spectra, evaluated over a discrete mesh (typically a discretization of the Brillouin zone), that is connected to its mesh neighbors into a linearly-interpolated approximation of the AbstractHamiltonian's bandstructure.

  • SelfEnergy: an operator Σ(ω) defined to act on a LatticeSlice of an AbstractHamiltonian that depends on energy ω.

  • OpenHamiltonian: an AbstractHamiltonian combined with a set of SelfEnergies

  • GreenFunction: an OpenHamiltonian combined with an AbstractGreenSolver, which is an algorithm that can in general compute the retarded or advanced Green function at any energy between any subset of sites of the underlying lattice.

    • GreenSlice: a GreenFunction evaluated on a specific set of sites, but at an unspecified energy
    • GreenSolution: a GreenFunction evaluated at a specific energy, but on an unspecified set of sites
  • OrbitalSliceArray: an AbstractArray that can be indexed with a SiteSelector, in addition to the usual scalar indexing. Particular cases are OrbitalSliceMatrix and OrbitalSliceVector. This is the most common type obtained from GreenFunctions and observables obtained from them.

  • Observables: Supported observables, obtained from Green functions using various algorithms, include local density of states, density matrices, current densities, transmission probabilities, conductance and Josephson currents

+Glossary · Quantica.jl

Glossary

This is a summary of the type of objects you will be studying.

  • Sublat: a sublattice, representing a number of identical sites within the unit cell of a bounded or unbounded lattice. Each site has a position in an E-dimensional space (E is called the embedding dimension). All sites in a given Sublat will be able to hold the same number of orbitals, and they can be thought of as identical atoms. Each Sublat in a Lattice can be given a unique name, by default :A, :B, etc.

  • Lattice: a collection of Sublats plus a collection of L Bravais vectors that define the periodicity of the lattice. A bounded lattice has L=0, and no Bravais vectors. A Lattice with L > 0 can be understood as a periodic (unbounded) collection of unit cells, each containing a set of sites, each of which belongs to a different sublattice.

  • SiteSelector: a rule that defines a subset of sites in a Lattice (not necessarily restricted to a single unit cell)

  • HopSelector: a rule that defines a subset of site pairs in a Lattice (not necessarily restricted to the same unit cell)

  • LatticeSlice: a finite subset of sites in a Lattice, defined by their cell index (an L-dimensional integer vector, usually denoted by n or cell) and their site index within the unit cell (an integer). A LatticeSlice an be constructed by combining a Lattice and a (bounded) SiteSelector.

  • AbstractModel: either a TightBindingModel or a ParametricModel

    • TightBindingModel: a set of HoppingTerms and OnsiteTerms
      • OnsiteTerm: a rule that, applied to a single site, produces a scalar or a (square) matrix that represents the intra-site Hamiltonian elements (single or multi-orbital)
      • HoppingTerm: a rule that, applied to a pair of sites, produces a scalar or a matrix that represents the inter-site Hamiltonian elements (single or multi-orbital)
    • ParametricModel: a set of ParametricOnsiteTerms and ParametricHoppingTerms
      • ParametricOnsiteTerm: an OnsiteTerm that depends on a set of free parameters that can be adjusted, and that may or may not have a default value
      • ParametricHoppingTerm: a HoppingTerm that depends on parameters, like ParametricOnsiteTerm above
  • AbstractHamiltonian: either a Hamiltonian or a ParametricHamiltonian

    • Hamiltonian: a Lattice combined with a TightBindingModel.

      It also includes a specification of the number of orbitals in each Sublat in the Lattice. A Hamiltonian represents a tight-binding Hamiltonian sharing the same periodicity as the Lattice (it is translationally invariant under Bravais vector shifts).

    • ParametricHamiltonian: like the above, but using a ParametricModel, which makes it dependent on a set of free parameters that can be efficiently adjusted.

    An h::AbstractHamiltonian can be used to produce a Bloch matrix h(ϕ; params...) of the same size as the number of orbitals per unit cell, where ϕ = [ϕᵢ...] are Bloch phases and params are values for the free parameters, if any.

  • Spectrum: the set of eigenpairs (eigenvalues and corresponding eigenvectors) of a Bloch matrix. It can be computed with a number of EigenSolvers.

  • Bandstructure: a collection of spectra, evaluated over a discrete mesh (typically a discretization of the Brillouin zone), that is connected to its mesh neighbors into a linearly-interpolated approximation of the AbstractHamiltonian's bandstructure.

  • SelfEnergy: an operator Σ(ω) defined to act on a LatticeSlice of an AbstractHamiltonian that depends on energy ω.

  • OpenHamiltonian: an AbstractHamiltonian combined with a set of SelfEnergies

  • GreenFunction: an OpenHamiltonian combined with an AbstractGreenSolver, which is an algorithm that can in general compute the retarded or advanced Green function at any energy between any subset of sites of the underlying lattice.

    • GreenSlice: a GreenFunction evaluated on a specific set of sites, but at an unspecified energy
    • GreenSolution: a GreenFunction evaluated at a specific energy, but on an unspecified set of sites
  • OrbitalSliceArray: an AbstractArray that can be indexed with a SiteSelector, in addition to the usual scalar indexing. Particular cases are OrbitalSliceMatrix and OrbitalSliceVector. This is the most common type obtained from GreenFunctions and observables obtained from them.

  • Observables: Supported observables, obtained from Green functions using various algorithms, include local density of states, density matrices, current densities, transmission probabilities, conductance and Josephson currents

diff --git a/dev/tutorial/greenfunctions/index.html b/dev/tutorial/greenfunctions/index.html index 605744bf..de021afd 100644 --- a/dev/tutorial/greenfunctions/index.html +++ b/dev/tutorial/greenfunctions/index.html @@ -100,4 +100,4 @@ julia> gx1 = sum(abs2, g(0.1)[siteselector(), 1], dims = 2); -julia> qplot(h, hide = :hops, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], minmaxsiteradius = (0, 2), sitecolormap = :balance)Green function from a contact on the right
Caveat for multiorbital systems

Since, currently, g(ω)[sᵢ, sⱼ] yields a Matrix over orbitals (instead of over sites), the above example requires single-orbital sites to work. In the future we will probably introduce a way to slice a GreenSolution over sites, similar to the way diagonal works. For the moment, one can use observables like ldos for visualization (see next section), which are all site-based by default.

+julia> qplot(h, hide = :hops, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], minmaxsiteradius = (0, 2), sitecolormap = :balance)Green function from a contact on the right
Caveat for multiorbital systems

Since, currently, g(ω)[sᵢ, sⱼ] yields a Matrix over orbitals (instead of over sites), the above example requires single-orbital sites to work. In the future we will probably introduce a way to slice a GreenSolution over sites, similar to the way diagonal works. For the moment, one can use observables like ldos for visualization (see next section), which are all site-based by default.

diff --git a/dev/tutorial/hamiltonians/index.html b/dev/tutorial/hamiltonians/index.html index 980db679..f0ed6706 100644 --- a/dev/tutorial/hamiltonians/index.html +++ b/dev/tutorial/hamiltonians/index.html @@ -115,4 +115,4 @@ Onsites : 0 Hoppings : 6 Coordination : 3.0 - Parameters : [:p]

The coupling keyword, available when combining h::AbstractHamiltonians, is a hopping model that is applied between each h. It can be constrained as usual with hopselectors and also be parametric. If either coupling or any of the combined h is parametric, the result of combine will be a ParametricHamiltonian, or a Hamiltonian otherwise.

The objects to be combined must satisfy some conditions:

  • They must have the same Bravais vectors (modulo reorderings), which will be then inherited by the combined object.
  • They must have the same position type (the T in AbstractHamiltonian{T} and Lattice{T})
  • They must have no repeated sublattice names among them (unless the combined object is non-parametric)
+ Parameters : [:p]

The coupling keyword, available when combining h::AbstractHamiltonians, is a hopping model that is applied between each h. It can be constrained as usual with hopselectors and also be parametric. If either coupling or any of the combined h is parametric, the result of combine will be a ParametricHamiltonian, or a Hamiltonian otherwise.

The objects to be combined must satisfy some conditions:

  • They must have the same Bravais vectors (modulo reorderings), which will be then inherited by the combined object.
  • They must have the same position type (the T in AbstractHamiltonian{T} and Lattice{T})
  • They must have no repeated sublattice names among them (unless the combined object is non-parametric)
diff --git a/dev/tutorial/lattices/index.html b/dev/tutorial/lattices/index.html index 9b9a92dd..113d4c74 100644 --- a/dev/tutorial/lattices/index.html +++ b/dev/tutorial/lattices/index.html @@ -109,4 +109,4 @@ [0.5, 1.0]

Currying: chaining transformations with the |> operator

Many functions in Quantica.jl have a "curried" version that allows them to be chained together using the pipe operator |>.

Definition of currying

The curried version of a function f(x1, x2...) is f´ = x1 -> f(x2...), so that the curried form of f(x1, x2...) is x2 |> f´(x2...), or f´(x2...)(x1). This gives the first argument x1 a privileged role. Users of object-oriented languages such as Python may find this use of the |> operator somewhat similar to the way the dot operator works there (i.e. x1.f(x2...)).

The last example above can then be written as

julia> LP.honeycomb(a0 = √3) |> transform(f) |> translate(δr) |> sites
 2-element Vector{SVector{2, Float64}}:
  [-0.5, 1.0]
- [0.5, 1.0]

This type of curried syntax is natural in Quantica, and will be used extensively in this tutorial.

+ [0.5, 1.0]

This type of curried syntax is natural in Quantica, and will be used extensively in this tutorial.

diff --git a/dev/tutorial/models/index.html b/dev/tutorial/models/index.html index 7f204c69..e0944b94 100644 --- a/dev/tutorial/models/index.html +++ b/dev/tutorial/models/index.html @@ -84,4 +84,4 @@ Hopping range : Inf Reverse hops : false Argument type : spatial - Parameters : [:B]

The difference with model_perierls is that model_perierls! will never add any new hoppings. It will only modify previously existing hoppings in a model. Modifiers are not models themselves, and cannot be summed to other models. They are instead meant to be applied sequentially after applying a model.

In the next section we show how models and modifiers can be used in practice to construct Hamiltonians.

Mind the `;`

While syntax like onsite(2, sublats = :B) and onsite(2; sublats = :B) are equivalent in Julia, due to the way keyword arguments are parsed, the same is not true for macro calls like @onsite, @onsite!, @hopping and @hopping!. These macros just emulate the function call syntax. But to work you must currently always use the ; separator for keywords. Hence, something like @onsite((; p) -> p; sublats = :B) works, but @onsite((; p) -> p, sublats = :B) does not.

+ Parameters : [:B]

The difference with model_perierls is that model_perierls! will never add any new hoppings. It will only modify previously existing hoppings in a model. Modifiers are not models themselves, and cannot be summed to other models. They are instead meant to be applied sequentially after applying a model.

In the next section we show how models and modifiers can be used in practice to construct Hamiltonians.

Mind the `;`

While syntax like onsite(2, sublats = :B) and onsite(2; sublats = :B) are equivalent in Julia, due to the way keyword arguments are parsed, the same is not true for macro calls like @onsite, @onsite!, @hopping and @hopping!. These macros just emulate the function call syntax. But to work you must currently always use the ; separator for keywords. Hence, something like @onsite((; p) -> p; sublats = :B) works, but @onsite((; p) -> p, sublats = :B) does not.

diff --git a/dev/tutorial/observables/index.html b/dev/tutorial/observables/index.html index 1b13a688..e02a5dc3 100644 --- a/dev/tutorial/observables/index.html +++ b/dev/tutorial/observables/index.html @@ -8,43 +8,44 @@ kernel : LinearAlgebra.UniformScaling{Bool}(true) julia> qplot(h, hide = :hops, sitecolor = d, siteradius = d, minmaxsiteradius = (0, 2), sitecolormap = :balance)LDOS

Note that d[sites...] produces a vector with the LDOS at sites defined by siteselector(; sites...) (d[] is the ldos over all sites). We can also define a kernel to be traced over orbitals to obtain the spectral density of site-local observables (see diagonal slicing in the preceding section).

Density matrix

We can also compute the convolution of the density of states with the Fermi distribution f(ω)=1/(exp((ω-μ)/kBT) + 1), which yields the density matrix in thermal equilibrium, at a given temperature kBT and chemical potential μ. This is computed with ρ = densitymatrix(gs, (ωmin, ωmax)). Here gs = g[sites...] is a GreenSlice, and (ωmin, ωmax) are integration bounds (they should span the full bandwidth of the system). Then, ρ(µ, kBT = 0; params...) will yield a matrix over the selected sites for a set of model params.

julia> ρ = densitymatrix(g[region = RP.circle(1)], (-0.1, 8.1))
-DensityMatrix: density matrix on specified sites using solver of type DensityMatrixIntegratorSolver
+DensityMatrix{DensityMatrixIntegratorSolver}: density matrix on specified sites
 
 julia> @time ρ(4)
-  6.150548 seconds (57.84 k allocations: 5.670 GiB, 1.12% gc time)
-5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
-          0.5+0.0im          -7.34893e-10-3.94035e-15im  0.204478+1.9366e-14im   -7.34889e-10-1.44892e-15im  -5.70089e-10+5.48867e-15im
- -7.34893e-10+3.94035e-15im           0.5+0.0im          0.200693-2.6646e-14im   -5.70089e-10-1.95251e-15im  -7.34891e-10-2.13804e-15im
-     0.204478-1.9366e-14im       0.200693+2.6646e-14im        0.5+0.0im              0.200693+3.55692e-14im      0.204779-4.27255e-14im
- -7.34889e-10+1.44892e-15im  -5.70089e-10+1.95251e-15im  0.200693-3.55692e-14im           0.5+0.0im          -7.34885e-10-3.49861e-15im
- -5.70089e-10-5.48867e-15im  -7.34891e-10+2.13804e-15im  0.204779+4.27255e-14im  -7.34885e-10+3.49861e-15im           0.5+0.0im

Note that the diagonal is 0.5, indicating half-filling.

The default algorithm used here is slow, as it relies on numerical integration in the complex plane. Some GreenSolvers have more efficient implementations. If they exist, they can be accessed by omitting the (ωmin, ωmax) argument. For example, using GS.Spectrum:

julia> @time g = h |> greenfunction(GS.Spectrum());
- 37.638522 seconds (105 allocations: 2.744 GiB, 0.79% gc time)
+  4.594645 seconds (111.82 k allocations: 4.890 GiB, 2.81% gc time, 0.86% compilation time)
+5×5 OrbitalSliceMatrix{ComplexF64,Array}:
+          0.5+0.0im          -7.35075e-10+3.40256e-15im  0.204478+4.46023e-14im  -7.35077e-10-1.13342e-15im  -5.70426e-10-2.22213e-15im
+ -7.35075e-10-3.40256e-15im           0.5+0.0im          0.200693-4.46528e-14im  -5.70431e-10+3.53853e-15im  -7.35092e-10-4.07992e-16im
+     0.204478-4.46023e-14im      0.200693+4.46528e-14im       0.5+0.0im              0.200693+6.7793e-14im       0.204779-6.78156e-14im
+ -7.35077e-10+1.13342e-15im  -5.70431e-10-3.53853e-15im  0.200693-6.7793e-14im            0.5+0.0im            -7.351e-10+2.04708e-15im
+ -5.70426e-10+2.22213e-15im  -7.35092e-10+4.07992e-16im  0.204779+6.78156e-14im    -7.351e-10-2.04708e-15im           0.5+0.0im

Note that the diagonal is 0.5, indicating half-filling.

The default algorithm used here is slow, as it relies on numerical integration in the complex plane. Some GreenSolvers have more efficient implementations. If they exist, they can be accessed by omitting the (ωmin, ωmax) argument. For example, using GS.Spectrum:

julia> @time g = h |> greenfunction(GS.Spectrum());
+ 18.249136 seconds (75 allocations: 1.567 GiB, 0.67% gc time)
 
 julia> ρ = densitymatrix(g[region = RP.circle(1)])
-DensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver
-
-julia> @time ρ(4)
-  0.001659 seconds (9 allocations: 430.906 KiB)
-5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
-          0.5+0.0im  -2.21437e-15+0.0im  0.204478+0.0im   2.67668e-15+0.0im   3.49438e-16+0.0im
- -2.21437e-15+0.0im           0.5+0.0im  0.200693+0.0im  -1.40057e-15+0.0im  -2.92995e-15+0.0im
-     0.204478+0.0im      0.200693+0.0im       0.5+0.0im      0.200693+0.0im      0.204779+0.0im
-  2.67668e-15+0.0im  -1.40057e-15+0.0im  0.200693+0.0im           0.5+0.0im   1.81626e-15+0.0im
-  3.49438e-16+0.0im  -2.92995e-15+0.0im  0.204779+0.0im   1.81626e-15+0.0im           0.5+0.0im

Note, however, that the computation of g is much slower in this case, due to the need of a full diagonalization. A better algorithm choice in this case is GS.KPM. It requires, however, that we define the region for the density matrix beforehand, as a nothing contact.

julia> @time g = h |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 10000, bandrange = (0,8)));
-Computing moments: 100%|█████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01
-  2.065083 seconds (31.29 k allocations: 11.763 MiB)
+DensityMatrix{DensityMatrixSpectrumSolver}: density matrix on specified sites
+
+julia> @time ρ(4)  # second-run timing
+  0.029662 seconds (7 allocations: 688 bytes)
+5×5 OrbitalSliceMatrix{ComplexF64,Array}:
+         0.5+0.0im   -6.6187e-16+0.0im  0.204478+0.0im   2.49658e-15+0.0im  -2.6846e-16+0.0im
+ -6.6187e-16+0.0im           0.5+0.0im  0.200693+0.0im  -2.01174e-15+0.0im   1.2853e-15+0.0im
+    0.204478+0.0im      0.200693+0.0im       0.5+0.0im      0.200693+0.0im     0.204779+0.0im
+ 2.49658e-15+0.0im  -2.01174e-15+0.0im  0.200693+0.0im           0.5+0.0im  1.58804e-15+0.0im
+ -2.6846e-16+0.0im    1.2853e-15+0.0im  0.204779+0.0im   1.58804e-15+0.0im          0.5+0.0im
+

Note, however, that the computation of g is much slower in this case, due to the need of a full diagonalization. A better algorithm choice in this case is GS.KPM. It requires, however, that we define the region for the density matrix beforehand, as a nothing contact.

julia> @time g = h |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 10000, bandrange = (0,8)));
+Computing moments: 100%|███████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01
+  1.360412 seconds (51.17 k allocations: 11.710 MiB)
 
 julia> ρ = densitymatrix(g[1])
-DensityMatrix: density matrix on specified sites with solver of type DensityMatrixKPMSolver
+DensityMatrix{DensityMatrixKPMSolver}: density matrix on specified sites
 
 julia> @time ρ(4)
-  0.006580 seconds (3 allocations: 1.156 KiB)
-5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
+  0.004024 seconds (3 allocations: 688 bytes)
+5×5 OrbitalSliceMatrix{ComplexF64,Array}:
          0.5+0.0im  2.15097e-17+0.0im   0.20456+0.0im  2.15097e-17+0.0im   3.9251e-17+0.0im
  2.15097e-17+0.0im          0.5+0.0im  0.200631+0.0im  1.05873e-16+0.0im  1.70531e-18+0.0im
      0.20456+0.0im     0.200631+0.0im       0.5+0.0im     0.200631+0.0im      0.20482+0.0im
  2.15097e-17+0.0im  1.05873e-16+0.0im  0.200631+0.0im          0.5+0.0im  1.70531e-18+0.0im
-  3.9251e-17+0.0im  1.70531e-18+0.0im   0.20482+0.0im  1.70531e-18+0.0im          0.5+0.0im

Current

A similar computation can be done to obtain the current density, using J = current(g(ω), direction = missing). This time J[sᵢ, sⱼ] yields a sparse matrix of current densities along a given direction for each hopping (or the current norm if direction = missing). Passing J as a hopping shader yields the equilibrium current in a system. In the above example we can add a magnetic flux to make this current finite

julia> h = LP.square() |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1])))) |> onsite(4) - @hopping((r, dr; B = 0.1) -> cis(B * dr[1] * r[2]));
+  3.9251e-17+0.0im  1.70531e-18+0.0im   0.20482+0.0im  1.70531e-18+0.0im          0.5+0.0im
Alternative integration paths

The integration algorithm allows many different integration paths that can be adjusted to each problem, see the Paths docstring. Another versatile choice is Paths.radial(ωrate, ϕ). This one is called with ϕ = π/4 when doing ρ = densitymatrix(gs::GreenSlice, ωrate::Number). In the example above this is slightly faster than the (ωmin, ωmax) choice, which resorts to Paths.sawtooth(ωmin, ωmax).

Current

A similar computation can be done to obtain the current density, using J = current(g(ω), direction = missing). This time J[sᵢ, sⱼ] yields a sparse matrix of current densities along a given direction for each hopping (or the current norm if direction = missing). Passing J as a hopping shader yields the equilibrium current in a system. In the above example we can add a magnetic flux to make this current finite

julia> h = LP.square() |> supercell(region = r -> norm(r) < 40*(1+0.2*cos(5*atan(r[2],r[1])))) |> onsite(4) - @hopping((r, dr; B = 0.1) -> cis(B * dr[1] * r[2]));
 
 julia> g = h |> greenfunction;
 
@@ -111,40 +112,27 @@
     Coordination     : 3.7448
 
 julia> J = josephson(g[1], 4.1)
-Integrator: Complex-plane integrator
-  Integration path    : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)
-  Integration options : (atol = 1.0e-7,)
-  Integrand:          :
-  JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy
-    kBT                     : 0.0
-    Contact                 : 1
-    Number of phase shifts  : 0
+Josephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact
 
 julia> qplot(g, children = (; sitecolor = :blue))
Josephson junction

In this case we have chosen to introduce the superconducting leads with a model self-energy, corresponding to a BCS bulk, but any other self-energy form could be used. We have introduced the phase difference (phase) as a model parameter. We can now evaluate the zero-temperature Josephson current simply with

julia> J(phase = 0)
--1.974396994480587e-16
+1.992660837638158e-12
 
 julia> J(phase = 0.2)
-0.004617597139699372

Note that finite temperatures can be taken using the kBT keyword argument for josephson, see docstring for details.

One is often interested in the critical current, which is the maximum of the Josephson current over all phase differences. Quantica.jl can compute the integral over a collection of phase differences simultaneously, which is more efficient that computing them one by one. This is done with

julia> φs = subdiv(0, pi, 11); J = josephson(g[1], 4.1; phases = φs)
-  Integration path    : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)
-  Integration options : (atol = 1.0e-7,)
-  Integrand:          :
-  JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy
-    kBT                     : 0.0
-    Contact                 : 1
-    Number of phase shifts  : 11
+0.0046175971391935605

Note that finite temperatures can be taken using the kBT keyword argument for josephson, see docstring for details.

One is often interested in the critical current, which is the maximum of the Josephson current over all phase differences. Quantica.jl can compute the integral over a collection of phase differences simultaneously, which is more efficient that computing them one by one. This is done with

julia> φs = subdiv(0, pi, 11); J = josephson(g[1], 4.1; phases = φs)
+Josephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact
 
 julia> Iφ = J()
 11-element Vector{Float64}:
- 1.868862401627357e-14
- 0.007231421775452674
- 0.014242855188877
- 0.02081870760779799
- 0.026752065104401878
- 0.031847203848574666
- 0.0359131410974842
- 0.03871895510547465
- 0.039762442694035505
- 0.03680096751905469
- 2.7677727119798235e-14
-
-julia> f = Figure(); a = Axis(f[1,1], xlabel = "φ", ylabel = "I [e/h]"); lines!(a, φs, Iφ); scatter!(a, φs, Iφ); f
Josephson junction current-phase relation + -6.361223111882911e-13 + 0.007231421776215144 + 0.01424285518831463 + 0.020818707606469377 + 0.026752065101976884 + 0.031847203846513975 + 0.035913141096514584 + 0.038718955102068034 + 0.03976244268586444 + 0.036800967573567184 + -1.437196514806921e-12 + +julia> f = Figure(); a = Axis(f[1,1], xlabel = "φ", ylabel = "I [e/h]"); lines!(a, φs, Iφ); scatter!(a, φs, Iφ); fJosephson junction current-phase relation diff --git a/dev/tutorial/tutorial/index.html b/dev/tutorial/tutorial/index.html index 53973ae0..59b5a18d 100644 --- a/dev/tutorial/tutorial/index.html +++ b/dev/tutorial/tutorial/index.html @@ -1,2 +1,2 @@ -Welcome · Quantica.jl

Tutorial

Welcome to the Quantica.jl tutorial!

Here you will learn how to use Quantica.jl to build and compute properties of tight-binding models. This includes

  • Defining general Lattices in arbitrary dimensions
  • Defining generic tight-binding Models with arbitrary parameter dependences
  • Building Hamiltonians of mono- or multiorbital systems by combining Lattices and Models
  • Computing Bandstructures of Hamiltonians
  • Computing GreenFunctions of Hamiltonians or OpenHamiltonians (i.e. Hamiltonians with attached self-energies from other Hamiltonians, such as leads).
  • Computing Observables from Green functions, such as spectral densities, current densities, local and nonlocal conductances, Josephson currents, critical currents, transmission probabilities, etc.

Check the menu on the left for shortcuts to the relevant sections.

Check the docstrings

Full usage instructions on all Quantica.jl functions can be found here or within the Julia REPL by querying their docstrings. For example, to obtain details on the hamiltonian function or on the available LatticePresets, just type ?hamiltonian or ?LatticePresets.

+Welcome · Quantica.jl

Tutorial

Welcome to the Quantica.jl tutorial!

Here you will learn how to use Quantica.jl to build and compute properties of tight-binding models. This includes

  • Defining general Lattices in arbitrary dimensions
  • Defining generic tight-binding Models with arbitrary parameter dependences
  • Building Hamiltonians of mono- or multiorbital systems by combining Lattices and Models
  • Computing Bandstructures of Hamiltonians
  • Computing GreenFunctions of Hamiltonians or OpenHamiltonians (i.e. Hamiltonians with attached self-energies from other Hamiltonians, such as leads).
  • Computing Observables from Green functions, such as spectral densities, current densities, local and nonlocal conductances, Josephson currents, critical currents, transmission probabilities, etc.

Check the menu on the left for shortcuts to the relevant sections.

Check the docstrings

Full usage instructions on all Quantica.jl functions can be found here or within the Julia REPL by querying their docstrings. For example, to obtain details on the hamiltonian function or on the available LatticePresets, just type ?hamiltonian or ?LatticePresets.