From 83f15236e29859aa4d514356540080a5cd442dc8 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Thu, 12 Oct 2023 17:23:55 +0000 Subject: [PATCH] build based on 6eb68db --- dev/api/index.html | 64 ++++++++++++------------- dev/assets/four_terminal_T.png | Bin 59003 -> 62037 bytes dev/assets/four_terminal_cond.png | Bin 0 -> 40117 bytes dev/examples/index.html | 2 +- dev/index.html | 2 +- dev/search/index.html | 2 +- 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 | 16 +++++-- dev/tutorial/tutorial/index.html | 2 +- 15 files changed, 55 insertions(+), 47 deletions(-) create mode 100644 dev/assets/four_terminal_cond.png diff --git a/dev/api/index.html b/dev/api/index.html index b1bf8375..51b7377b 100644 --- a/dev/api/index.html +++ b/dev/api/index.html @@ -9,7 +9,7 @@ -0.38196601125010465 + 3.686368662666227e-16im -0.6180339887498938 + 6.015655020129746e-17im 0.6180339887498927 + 2.6478518218421853e-16im - 0.38196601125010476 - 1.741261108320361e-16im

See also

`spectrum`, `bands`
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.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.
    • 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, 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 LatticePresets. Currently supported hamiltonians are

HP.graphene(; kw...)
+  0.38196601125010476 - 1.741261108320361e-16im

See also

`spectrum`, `bands`
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.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.
    • 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, 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 LatticePresets. 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
@@ -18,7 +18,7 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 0
   Hoppings         : 315684
-  Coordination     : 28.27696

See also

`LatticePresets`, `RegionPresets`
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`
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
@@ -37,7 +37,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`
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`
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
@@ -48,7 +48,7 @@
 false
 
 julia> RegionPresets.circle(10)(0, 0, 20)
-true

See also

`LatticePresets`, `HamiltonianPresets`
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
Base.reverseFunction
reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})

Build a new lattice or hamiltonian with the orientation of all Bravais vectors 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 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.attachFunction
attach(h::AbstractHamiltonian, args..; sites...)
+true

See also

`LatticePresets`, `HamiltonianPresets`
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
Base.reverseFunction
reverse(lat_or_h::Union{Lattice,AbstractHamiltonian})

Build a new lattice or hamiltonian with the orientation of all Bravais vectors 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 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.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; 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. 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 null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to defining a contact on said sites, 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). The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the lead unit cell, after applying transform to the latter. If they don't, 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() |> hamiltonian(hopping(1)) |> supercell((0,0,1), region = RP.square(4)) |> greenfunction(GS.Schur(boundary = 0));
@@ -56,7 +56,7 @@
 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));
+

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
@@ -77,14 +77,14 @@
   Subbands  : 1
   Vertices  : 97
   Edges     : 96
-  Simplices : 96

See also

`spectrum`, `subdiv`
source
Quantica.bravais_matrixFunction
bravais_matrix(lat::Lattice)
+  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.cellsitesFunction
cellsites(cell_indices, site_indices)

Simple selector of sites with given site_indices in a given cell at cell_indices. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_indices should be a collection of L integers, where L is the lattice dimension.

See also

`siteselector`
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::AbstractHamiltonians...; 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.

Examples

julia> # Building Bernal-stacked bilayer graphene
+

See also

`lattice`
source
Quantica.cellsitesFunction
cellsites(cell_indices, site_indices)

Simple selector of sites with given site_indices in a given cell at cell_indices. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_indices should be a collection of L integers, where L is the lattice dimension.

See also

`siteselector`
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::AbstractHamiltonians...; 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.

Examples

julia> # Building Bernal-stacked bilayer graphene
 
 julia> hbot = HP.graphene(a0 = 1, dim = 3); htop = translate(hbot, (0, 1/√3, 1/√3));
 
@@ -100,7 +100,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));
@@ -113,7 +113,7 @@
   Bias contact     : 1
 
 julia> G(0.2)
-2.999999999999999

See also

`greenfunction`, `ldos`, `current`, `josephson`, `transmission`
source
Quantica.currentFunction
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...]
+2.999999999999999

See also

`greenfunction`, `ldos`, `current`, `josephson`, `transmission`
source
Quantica.currentFunction
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.

Example

julia> # A semi-infinite 1D lead with a magnetic field `B`
 
 julia> g = LP.square() |> hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> supercell((1,0), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
@@ -134,7 +134,7 @@
   ⋅           7.77156e-16   ⋅
  7.77156e-16   ⋅           5.55112e-16
   ⋅           5.55112e-16   ⋅
-

See also

`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`
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.greenfunctionFunction
greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::GreenSolver)

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]
+

See also

`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`
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.greenfunctionFunction
greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::GreenSolver)

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)]

If kernel = missing, efficiently construct diag(g[i, i]). If kernel is a matrix, return tr(g[site, site] * kernel) over each site encoded in i. Note that if there are several orbitals per site, these will have different length (i.e. number of orbitals vs number of sites). See also diagonal.

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 dense and has scalar elements, so that any orbital structure on each site is flattened.

Example

julia> g = LP.honeycomb() |> hamiltonian(@hopping((; t = 1) -> t)) |> supercell(region = RP.circle(10)) |> greenfunction(GS.SparseLU())
@@ -162,7 +162,7 @@
 GreenSlice{Float64,2,0}: Green function at arbitrary energy, but at a fixed lattice positions
 
 julia> gω[ss] == gs(0.1; t = 2)
-true

See also

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

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

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

See also

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

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

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

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

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 indivisual 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.

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
@@ -179,7 +179,7 @@
      ⋅          ⋅      0.0+0.0im  3.0+0.0im
      ⋅          ⋅      3.0+0.0im  0.0+0.0im
  0.0+0.0im  3.0+0.0im      ⋅          ⋅
- 3.0+0.0im  0.0+0.0im      ⋅          ⋅

See also

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

See also

`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`
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}:
@@ -203,7 +203,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
@@ -237,7 +237,7 @@
   Element type     : scalar (ComplexF64)
   Onsites          : 0
   Hoppings         : 18
-  Coordination     : 9.0

See also

`siteselector`, `lattice`, `hopping`, `@hopping`, `@hopping!`
source
Quantica.josephsonFunction
josephson(gs::GreenSlice, ωmax; kBT = 0.0, phases = missing, imshift = missing, slope = 1, post = real, atol = 1e-7, quadgk_opts...)

For a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a partially evaluated object J::Integrator representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated from -ωmax to ωmax (or from -ωmax to 0 at zero temperature kBT = 0). 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]$.

Full evaluation

J(; params...)

Evaluate the Josephson current I_J for the given g parameters params, if any.

Keywords

  • kBT : temperature in same energy units as the Hamiltonian
  • 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) 0; 0 cis(ϕ/2)] rotation to the self energy, which is almost free. If missing, a single I_J is returned.
  • imshift: if missing the initial and final integration points ± ωmax are shifted by im * sqrt(eps(ωmax)), to avoid the real axis. Otherwise a shift im*imshift is applied (may be zero if ωmax is greater than the bandwidth).
  • slope: if non-zero, the integration will be performed along a piecewise-linear path in the complex plane (-ωmax, -ωmax/2 * (1+slope*im), 0, ωmax/2 * (1+slope*im), ωmax), taking advantage of the holomorphic integrand f(ω) j(ω) and the Cauchy Integral Theorem for faster convergence.
  • post: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero.
  • quadgk_opts : 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.0005 * SA[0 1; 1 0]) + 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.josephsonFunction
josephson(gs::GreenSlice, ωmax; kBT = 0.0, phases = missing, imshift = missing, slope = 1, post = real, atol = 1e-7, quadgk_opts...)

For a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a partially evaluated object J::Integrator representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated from -ωmax to ωmax (or from -ωmax to 0 at zero temperature kBT = 0). 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]$.

Full evaluation

J(; params...)

Evaluate the Josephson current I_J for the given g parameters params, if any.

Keywords

  • kBT : temperature in same energy units as the Hamiltonian
  • 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) 0; 0 cis(ϕ/2)] rotation to the self energy, which is almost free. If missing, a single I_J is returned.
  • imshift: if missing the initial and final integration points ± ωmax are shifted by im * sqrt(eps(ωmax)), to avoid the real axis. Otherwise a shift im*imshift is applied (may be zero if ωmax is greater than the bandwidth).
  • slope: if non-zero, the integration will be performed along a piecewise-linear path in the complex plane (-ωmax, -ωmax/2 * (1+slope*im), 0, ωmax/2 * (1+slope*im), ωmax), taking advantage of the holomorphic integrand f(ω) j(ω) and the Cauchy Integral Theorem for faster convergence.
  • post: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.
  • atol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero.
  • quadgk_opts : 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.0005 * SA[0 1; 1 0]) + 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;
 
@@ -262,7 +262,7 @@
   0.008147188939639644
   0.008844017741703502
   0.009272686515034255
- -1.7744618723033526e-12

See also

`greenfunction`,`ldos`, `current`, `conductance`, `transmission`
source
Quantica.latticeFunction
lattice(sublats::Sublat...; bravais = (), dim, type, names)
+ -1.7744618723033526e-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...]

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.

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
   Bravais vectors : Vector{Float32}[[1.0, 0.0, 0.0]]
@@ -275,7 +275,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 = I)

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 = I)

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 ρᵢ(ω) = -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.

Full evaluation

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

See also

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

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 = I)

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 ρᵢ(ω) = -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.

Full evaluation

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

Given a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build a vector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states.

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
@@ -301,7 +301,7 @@
  0.036802204179317045
 
 julia> ldos(g(0.2))[1] == -imag.(g[diagonal(1; kernel = I)](0.2)) ./ π
-true

See also

`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`
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...)
+true

See also

`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`
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}:
@@ -325,7 +325,7 @@
   Element type     : 2 × 2 blocks (ComplexF64)
   Onsites          : 64
   Hoppings         : 2048
-  Coordination     : 32.0

See also

`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`
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
+  Coordination     : 32.0

See also

`hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `hamiltonian`
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
@@ -355,9 +355,9 @@
 julia> h((0,0))
 2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
      ⋅      0.0-3.0im
- 0.0+3.0im      ⋅
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...)

Examples

julia> sites(LatticePresets.honeycomb(), :A)
+ 0.0+3.0im      ⋅
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...)

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)
@@ -370,11 +370,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]]
@@ -387,15 +387,15 @@
   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.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)
+    Sites         : (9, 9) --> 18 total per unit cell

See also

`supercell`, `siteselector`
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.honecycomb() |> hamiltonian(hopping(1)) |> supercell((1,-1), region = r->-2<r[2]<2) |> greenfunction(GS.Schur(boundary = 0));
 
@@ -410,10 +410,10 @@
 2.9999999410323537
 
 julia> T(0.2 + 0.00000000000001im)
-2.999999999999961

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.999999999999961

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.wrapFunction
wrap(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))

For an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new zero-dimensional h´::AbstractHamiltonian for all Bravais vectors have been eliminated by wrapping the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along wrapped 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 wrapped, and the resulting will have a finite lattice dimension .

Currying

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

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

Examples

julia> h2D = HP.graphene(); h1D = wrap(h2D, (:, 0.2))
+ [2.7+0.0im 0.0+0.0im; 0.0+0.0im 2.7+0.0im]                      ⋅
source
Quantica.wrapFunction
wrap(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))

For an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new zero-dimensional h´::AbstractHamiltonian for all Bravais vectors have been eliminated by wrapping the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along wrapped 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 wrapped, and the resulting will have a finite lattice dimension .

Currying

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

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

Examples

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

See also

`hamiltonian`, `supercell`
source
Quantica.@hoppingMacro
@hopping((; params...) -> t(; params...); hops...)
+true

See also

`hamiltonian`, `supercell`
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).

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)))
 ParametricModel: model with 1 term
@@ -446,7 +446,7 @@
   Onsites          : 0
   Hoppings         : 24
   Coordination     : 3.0
-  Parameters       : [:A, :t]

See also

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

See also

`onsite`, `hopping`, `@onsite`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`
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!.

Examples

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

See also

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

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `hamiltonian`
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).

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)
 ParametricModel: model with 2 terms
@@ -491,7 +491,7 @@
   Onsites          : 8
   Hoppings         : 0
   Coordination     : 0.0
-  Parameters       : [:dμ]

See also

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

See also

`onsite`, `hopping`, `@hopping`, `@onsite!`, `@hopping!`, `attach`, `hamiltonian`
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!.

Examples

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

See also

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

See also

`onsite`, `hopping`, `@onsite`, `@hopping`, `@hopping!`, `hamiltonian`
source diff --git a/dev/assets/four_terminal_T.png b/dev/assets/four_terminal_T.png index 5993b90ea40419dc905749caaad6dddb09f027fa..a114d0c4a59cd02d2afa17f0b16017ad3f91ca3f 100644 GIT binary patch literal 62037 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
1$w) z(vb?A7)AGN$f0;WKfW*+(_&e_O#RX8auSiMN4renlr=6X)%wlV$ELl#vi{VFBNZ|u zTw(O#&Sh%GrPGr4WQh;O79G6b#o7dVWhFVpWS4TmGk32DrZ1Yf@QE5|UjFb1+2ZC6 zc3;E-z(>>DToR|wUk$yC#`)W&?NA}zIfI`M)7k6sizyFOht|#sE`pOoNw;JTxc0X2 zinw5?`9u$HPIlb4Pc!NV4?MfWIiLyJQ&5=nr=%4aNNoA>`PpNB76sPIDVpy3Q6fW7(dd0~FZT)CMb zG$%-wBrRV{+%Z)thfO$V`0M67+htRR*S9^%%R-`VY@Ax}^kNyp2aDM&tPv zFNYwqcXq{lM0IS(GFLxa0V(8URzhlaE9NejGZc`L#vMZF5YU5!^Y<`ENCDfN}fO`}3g` zqsfTjb7kkxHCqCsi%Fp;!fM=qpdY(#AUCu%YtgK8SD-C)@+hx3`~;x4a5qIs8S>#x zt^WFyu_)S|4_q%u_rJyavU2d4INhx-tcNHmqdCuQPb^79UP+8MH?*2@74rRlA_)kN z@2H-Gvk7_&BV1y)@)xf9CWXLg$=@`$0xU~F_`HC^RO266>wnTXvR0I z+_<}7=QK30ko#_EE*mQ~%W9mNn8Hp+O?O5F^8ih^05NH3Vt)?%Ong6ZJ>~!fyV9ao z6&z^5JP|vD)IrJqw7ts4_>70vj8zx+7?C&fcd(O!Q<8RVI8fgjCe2gGjDAr|!+Sf_ z&)Pm#O+;|WmE<7bD~9R&>Z6X74gG^fJ{7dRr(z4`t2jViSbzzM4GX$Q_%6`etV0E{ zvJusNADKsaK|zXC5iELbw(mbI>a@kIL>CyMx(5e{6X~AtCJ~k} zsQ8`_!CVyTS5_l}?A#erPrhGm-rrdjO%u?va7X$33vN|>HRr$j!yskzw!CdwyBjyy zM&X318+Bq#D;@RZy+mb+(2O!Z>L|*++QStxGBFy7R!q`nXKlpL<bQsz(mUd_xZV9Db|BNs1qCpt9X^+X;~6+dYfv(KTh%;T!9~A7iUTe22j2 zpq12M^K2Iqw+T_D%eIj8=M76ZJ!5X!gGn;4{l6758(vv*pM41m}}lV3ElS` ze|=4EPNroKxDQAU$9Cf}h13h&;8C~=HM;W=sO{Vyh8&D)hftR%hda~xB1ZS=QvlTN zVGYT`@4%|B_OC%DJDgmpW!7Yu@;;zo&Vkj#(@JmBW3FL*pu)k^?&u8ci`kn2!tv_7U{u9=x!u{kZ ztdAh}ji2~-^mUWLfl%zsng0wz0^Td)stv|~pnSOsAW6~mmA-aFNu4*k{LuiAm_Y;Y z{^aPS%*q&t#!Pj*$f4V!HA0uOk=NUSq$*WI%}G zp!_zJ0IJ%DCp!-E94yIBY&by(7v5J9d7?-R7a&H>-yq6#3eM1d>U}^~^QdY1wzikg zbrBPM4GXKAS$`o*voB`*SI9fLPGK!GL#knR(4o3^KgHB+Ig^rQkaXQE)f*`d&Jp(O z0Bx4%jlzgsR0>&PjDiT#ARd@wCvF=(f7h)n&)d43ZG>8m9rXBQ(*DQJ@$Kxw z+SRDACho`qiyFwGnTZ^U7){G)fZ0%1Llz>Apsm8I+oGzLwpoWqwZFs%e}6tpA*Fu*noKsu3mW;%#{unSS=8J*MY{MH`)Uhb&BrNteIXi9`2JsnNCwSa+P~v#53k^h9XpSSys>eHww0COo{a1#ys;kl?B-p^VXU`6)T!BNa$A zbtem{J%n@a9*l|Y{TFUd?m;wTcR!3v+KQY5qsuV^r@o9s1dQN%mnKkA%$oK8*Q8bLva*J9r;o7EPqDgaA zX@22ZF-~M9IF>D;B6HhC-|ZluFm1J^K3e_(2n^e1r6yrB7(JYW2!$fHfj{Zy-to5g zv}Y^`gd)f7&)G70aOkW3>?I=`VmqfmQgDuA6A)lfg>4U#JbSJu4CeT4SPqeju zj7$aSEV+)akyyrv$6B@a2#Pxrenx)Ay|g z%{9}c>*E@|q+jyvyxv<7b~RwQ`W=U#U$@T_Rf6=pE2HgMWqNfL&n*8YG{m>8TG4Z1 z4E6)eK&jL!=+G=2kA{`;^HM^u3LQt$Iul)f``VcOCA}JIf&DB?t>%pgs)}l<(Ax

F%#W9$@3M?L`m2GtO5Rh>`itw*4I%{>!hy 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 diff --git a/dev/assets/four_terminal_cond.png b/dev/assets/four_terminal_cond.png new file mode 100644 index 0000000000000000000000000000000000000000..1cfbc0cdda41c13a0433d9da6ffda0e5860ef533 GIT binary patch literal 40117 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¬!KZvJWvh9di=PfK)qIb zFkN&XFiZM2yaKwo%i`&+tM4fV+;Z#D_*a^HGD-l^-b&WbMo2b9TjO6?O>!05(L%mN z_0{pzvYFdOoJ&4D%9GED-nZF6G!?Lp{f<_wVELNtV1cEN1lmLcM9oXU3Wop_*;VLv zWmJ7MswzaTW)#D2k?Q{s!vYF80kHryS%vYycc(RV99tNY=8fnGBcH0pJU0^%_@F;H z;M|tF?Co&tl%iRCd`V9Ff7U1r4kggUf%)C~|9`)|J2KhdF7vsU#xY>RegdkJqw{ti zJ=fd;>;eD}U_9l_Z>s`2g~+j)%`-A`=8KlM-TM0?N+LpvfnCY9zIIjL-e_`*>rHW& zt902_@=~d)T}e}O<mfp@Mlgtj!D0z3}!NKOGR&R3E)xL zKnFMJUpV?_VtV$)2iC>li}k)URf#)(pKw7%@j{*8uWeT@Tu7MSlxut3NxkB=(U!H- zC*=07DmGG5k~n$$R?Bf<{~6ej^U!cwc*YXmhXRJ@3I_S763N|5u+QFV z^c>dJ0!8FvCPAxbQxL=LpiD5QkD*w@&%O6Pd{`Z1vbI2AWF#jmQnw7ag+Gc(aDLsd zm498^?B-6B-;dn6ThFT0Cu6Au%;{_HzI}bV;TY0*ML`vlpr)qgrlO~(F8|K0LySTK d1Efax!~a{;nSl4i=D%hD0#8>zmvv4FO#oJWjDP?D literal 0 HcmV?d00001 diff --git a/dev/examples/index.html b/dev/examples/index.html index 11599faf..0851163f 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 0163e801..88154084 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/search/index.html b/dev/search/index.html index 9e1d96ab..a3a75fcc 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · Quantica.jl

Loading search...

    +Search · Quantica.jl

    Loading search...

      diff --git a/dev/search_index.js b/dev/search_index.js index 87a98103..3a3c9cf3 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"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::GreenSolver (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 Schur GreenSolver 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 ⟨i|(ω - H - Σ(ω))⁻¹|j⟩ inverse.","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","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.\nGS.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.\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":"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. - To specify ω (plus any parameters params in the underlying AbstractHamiltonian) we use the syntax g(ω; params...), which yields an gω::GreenSolution - 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. - 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 a Matrix","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 Matrix{ComplexF64}:\n -0.370342-0.0778282im 0.0575525-0.211484im 0.0245456-0.129385im 0.174425-0.155446im 0.100593+0.0134301im\n 0.0575525-0.211484im -0.0619157+0.0480224im 0.156603+0.256013im -0.342883+0.0760708im -0.0414971+0.0510385im\n 0.0245456-0.129385im 0.156603+0.256013im -0.13008-0.156987im 0.129202-0.139979im 0.155843-0.0597696im\n 0.174425-0.155446im -0.342883+0.0760708im 0.129202-0.139979im -0.0515859+0.000612582im 0.0298279+0.109486im\n 0.100593+0.0134301im -0.0414971+0.0510385im 0.155843-0.0597696im 0.0298279+0.109486im 0.00445114+0.0242172im\n\n julia> g(0.2)[siteselector(region = RP.circle(1, (0.5, 0))), 3]\n2×5 Matrix{ComplexF64}:\n -0.0051739-0.0122979im 0.258992+0.388052im 0.01413-0.192581im 0.258992+0.388052im -0.0051739-0.0122979im\n 0.265667+0.296249im 0.171343-0.022414im 0.285251+0.348008im 0.171247+0.0229456im 0.0532086+0.24404im","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 Vector{ComplexF64}:\n -0.34973634684887517 - 0.3118358260293383im\n -0.3497363468428337 - 0.3118358260293383im\n -0.349736346839396 - 0.31183582602933824im\n -0.34973634684543714 - 0.3118358260293383im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that we get a vector, which is equal to the diagonal diag(g(0.5)[cells = (0, 0)]). Like the g Matrix, 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 Vector{ComplexF64}:\n -1.1268039540527714e-11 - 2.3843717644870095e-17im\n 1.126802874880133e-11 + 1.9120152589671175e-17im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"which is zero in this spin-degenerate case","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 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/#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/#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 a GreenSolver, 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\nObservable: a physical observable that can be expressed in terms of a GreenFunction.\nExamples of supported observables include local density of states, current density, transmission probability, conductance and Josephson current","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, inspector = true)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"\"Kane-Mele","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The inspector = true keyword enables interactive tooltips in the visualization of h that 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 wrap, which makes h periodic along a number of its Bravais vectors, while leaving the rest unbounded.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> wrap(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 wrap(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 wrapping hoppings, while each colon leaves the lattice unbounded along the corresponding Bravais vector. In a way wrap is dual to supercell, in the sense that the 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. wrap(h, (ϕ₁, :))(ϕ₂) == h(ϕ₁, ϕ₂)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Caveat of the Bloch-wrap duality\nThe relation wrap(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 rapping hoppings added by wrap are already present in h, as in the case 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 wrap when models are position dependent.","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":"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 several pre-defined eigensolvers. 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\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\nAdditionally, to compute interior eigenvalues, we can use a shift-invert method around energy ϵ0 (uses LinearMaps and a LinearSolve.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\nIf the required packages are not already available, they will be automatically loaded when calling these solvers.\n\nExamples\n\njulia> h = HP.graphene(t0 = 1) |> supercell(10);\n\njulia> spectrum(h, (0,0), ES.ShiftInvert(ES.ArnoldiMethod(nev = 4), 0.0)) |> energies\n4-element Vector{ComplexF64}:\n -0.38196601125010465 + 3.686368662666227e-16im\n -0.6180339887498938 + 6.015655020129746e-17im\n 0.6180339887498927 + 2.6478518218421853e-16im\n 0.38196601125010476 - 1.741261108320361e-16im\n\nSee also\n\n`spectrum`, `bands`\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.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.\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, 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 LatticePresets. 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`\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`\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`\n\n\n\n\n\n","category":"module"},{"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/#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 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 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.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; 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. 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 null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to defining a contact on said sites, 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). The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the lead unit cell, after applying transform to the latter. If they don't, 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() |> 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\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.cellsites","page":"API","title":"Quantica.cellsites","text":"cellsites(cell_indices, site_indices)\n\nSimple selector of sites with given site_indices in a given cell at cell_indices. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_indices should be a collection of L integers, where L is the lattice dimension.\n\nSee also\n\n`siteselector`\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::AbstractHamiltonians...; 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\nExamples\n\njulia> # Building Bernal-stacked bilayer graphene\n\njulia> hbot = HP.graphene(a0 = 1, dim = 3); htop = translate(hbot, (0, 1/√3, 1/√3));\n\njulia> h2 = combine(hbot, htop; coupling = hopping(1, sublats = :B => :C) |> plusadjoint))\n┌ Warning: Renamed repeated sublattice :A to :C\n└ @ Quantica ~/.julia/dev/Quantica/src/types.jl:60\n┌ Warning: Renamed repeated sublattice :B to :D\n└ @ Quantica ~/.julia/dev/Quantica/src/types.jl:60\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)\n2.999999999999999\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(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\nExample\n\njulia> # A semi-infinite 1D lead with a magnetic field `B`\n\njulia> g = LP.square() |> hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> supercell((1,0), region = r->-2 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\n\nSee also\n\n`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`\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.greenfunction","page":"API","title":"Quantica.greenfunction","text":"greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::GreenSolver)\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\nIf kernel = missing, efficiently construct diag(g[i, i]). If kernel is a matrix, return tr(g[site, site] * kernel) over each site encoded in i. Note that if there are several orbitals per site, these will have different length (i.e. number of orbitals vs number of sites). See also diagonal.\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 dense and has scalar elements, so that any orbital structure on each site is flattened.\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\nSee also\n\n`GreenSolvers`, `diagonal`, `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 a Hamiltonian or ParametricHamiltonian by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building tight-binding models).\n\nhamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)\nhamiltonian(h::AbstractHamiltonian, modifiers...; orbitals = 1)\n\nCreate a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided modifiers (see @onsite! and @hopping! for details on defining modifiers).\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 indivisual 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\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\nSee also\n\n`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`\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.josephson","page":"API","title":"Quantica.josephson","text":"josephson(gs::GreenSlice, ωmax; kBT = 0.0, phases = missing, imshift = missing, slope = 1, post = real, atol = 1e-7, quadgk_opts...)\n\nFor a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a partially evaluated object J::Integrator representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated from -ωmax to ωmax (or from -ωmax to 0 at zero temperature kBT = 0). 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(ω) = (qeh) 2Tr(ΣʳᵢGʳ - GʳΣʳᵢ)τz.\n\nFull evaluation\n\nJ(; params...)\n\nEvaluate the Josephson current I_J for the given g parameters params, if any.\n\nKeywords\n\nkBT : temperature in same energy units as the Hamiltonian\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) 0; 0 cis(ϕ/2)] rotation to the self energy, which is almost free. If missing, a single I_J is returned.\nimshift: if missing the initial and final integration points ± ωmax are shifted by im * sqrt(eps(ωmax)), to avoid the real axis. Otherwise a shift im*imshift is applied (may be zero if ωmax is greater than the bandwidth).\nslope: if non-zero, the integration will be performed along a piecewise-linear path in the complex plane (-ωmax, -ωmax/2 * (1+slope*im), 0, ωmax/2 * (1+slope*im), ωmax), taking advantage of the holomorphic integrand f(ω) j(ω) and the Cauchy Integral Theorem for faster convergence.\npost: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero.\nquadgk_opts : 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.0005 * SA[0 1; 1 0]) + 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; phases = subdiv(0, pi, 10))\nIntegrator: Complex-plane integrator\n Integration path : (-4.0 + 1.4901161193847656e-8im, -2.0 + 2.000000014901161im, 0.0 + 1.4901161193847656e-8im)\n Integration options : ()\n Integrand: :\n JosephsonDensity{Float64} : Equilibrium (dc) Josephson current observable before integration over energy\n kBT : 0.0\n Contact : 1\n Number of phase shifts : 10\n\njulia> J()\n10-element Vector{Float64}:\n -6.751348391359149e-16\n 0.0016315088241546964\n 0.003213820056117238\n 0.004699191781510955\n 0.0060427526322931946\n 0.0072038354411029185\n 0.008147188939639644\n 0.008844017741703502\n 0.009272686515034255\n -1.7744618723033526e-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...]\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\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 = I)\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 = I)\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 ρᵢ(ω) = -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.\n\nFull evaluation\n\nρω[sites...]\nρs(ω; params...)\n\nGiven a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build a vector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states.\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 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.(g[diagonal(1; kernel = I)](0.2)) ./ π\ntrue\n\nSee also\n\n`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`\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.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.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\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.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.honecycomb() |> hamiltonian(hopping(1)) |> supercell((1,-1), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.honecycomb() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> T = transmission(g0[2, 1])\nTransmission: total transmission probability between two different contacts\n From contact : 1\n To contact : 2\n\njulia> T(0.2) # The difference from 3 is due to the automatic `im*sqrt(eps(Float64))` added to `ω`\n2.9999999410323537\n\njulia> T(0.2 + 0.00000000000001im)\n2.999999999999961\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.wrap","page":"API","title":"Quantica.wrap","text":"wrap(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))\n\nFor an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new zero-dimensional h´::AbstractHamiltonian for all Bravais vectors have been eliminated by wrapping the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along wrapped 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 wrapped, and the resulting h´ will have a finite lattice dimension L´.\n\nCurrying\n\nh |> wrap((ϕ₁, ϕ₂,...))\n\nCurrying syntax equivalent to wrap(h, (ϕ₁, ϕ₂,...)).\n\nExamples\n\njulia> h2D = HP.graphene(); h1D = wrap(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.@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\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 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`\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\nExamples\n\njulia> model = hopping(1); peierls = @hopping!((t, r, dr; A = r -> SA[0,0]) -> t * cis(-dr' * A(r)))\nOnsiteModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\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`\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\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 Parameters : [:dμ]\n ParametricOnsiteTerm{ParametricFunction{0}}\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1\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`\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\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 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`\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) - ldos: computes the local density of states at specific energy and sites - current: computes the local current density along specific directions, and at specific energy and sites - transmission: computes the total transmission between contacts - conductance: computes the differential conductance dIᵢ/dVⱼ between contacts i and j - josephson: 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 ρ = 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 ρ 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> ρ = 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 = ρ, siteradius = ρ, 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 ρ[sites...] produces a vector with the LDOS at sites defined by siteselector(; sites...) (ρ[] 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/#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() |> onsite(4) - hopping(1) |> supercell(region = RP.circle(100) | RP.rectangle((202, 50)) | RP.rectangle((50, 202)))\n\njulia> glead = LP.square() |> onsite(4) - 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 = sum(abs2, g(0.04)[siteselector(), 1], dims = 2);\n\njulia> qplot(hcentral, hide = :hops, siteoutline = 1, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], 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":"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(0, 4, 200);\n\njulia> T₂₁ω = @showprogress [T₂₁(ω) for ω in ωs]; T₃₁ω = @showprogress [T₃₁(ω) for ω in ωs];\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:05\nProgress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:04\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/#Josephson","page":"Observables","title":"Josephson","text":"","category":"section"},{"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 Parameters : [:B, :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 Parameters : [:t]\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 2","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 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.","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, inspector = true)","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, length = npoints) or collect(LinRange(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´ = 1) -> 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/#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":"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::GreenSolver (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 Schur GreenSolver 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 ⟨i|(ω - H - Σ(ω))⁻¹|j⟩ inverse.","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","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.\nGS.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.\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":"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. - To specify ω (plus any parameters params in the underlying AbstractHamiltonian) we use the syntax g(ω; params...), which yields an gω::GreenSolution - 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. - 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 a Matrix","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 Matrix{ComplexF64}:\n -0.370342-0.0778282im 0.0575525-0.211484im 0.0245456-0.129385im 0.174425-0.155446im 0.100593+0.0134301im\n 0.0575525-0.211484im -0.0619157+0.0480224im 0.156603+0.256013im -0.342883+0.0760708im -0.0414971+0.0510385im\n 0.0245456-0.129385im 0.156603+0.256013im -0.13008-0.156987im 0.129202-0.139979im 0.155843-0.0597696im\n 0.174425-0.155446im -0.342883+0.0760708im 0.129202-0.139979im -0.0515859+0.000612582im 0.0298279+0.109486im\n 0.100593+0.0134301im -0.0414971+0.0510385im 0.155843-0.0597696im 0.0298279+0.109486im 0.00445114+0.0242172im\n\n julia> g(0.2)[siteselector(region = RP.circle(1, (0.5, 0))), 3]\n2×5 Matrix{ComplexF64}:\n -0.0051739-0.0122979im 0.258992+0.388052im 0.01413-0.192581im 0.258992+0.388052im -0.0051739-0.0122979im\n 0.265667+0.296249im 0.171343-0.022414im 0.285251+0.348008im 0.171247+0.0229456im 0.0532086+0.24404im","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 Vector{ComplexF64}:\n -0.34973634684887517 - 0.3118358260293383im\n -0.3497363468428337 - 0.3118358260293383im\n -0.349736346839396 - 0.31183582602933824im\n -0.34973634684543714 - 0.3118358260293383im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"Note that we get a vector, which is equal to the diagonal diag(g(0.5)[cells = (0, 0)]). Like the g Matrix, 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 Vector{ComplexF64}:\n -1.1268039540527714e-11 - 2.3843717644870095e-17im\n 1.126802874880133e-11 + 1.9120152589671175e-17im","category":"page"},{"location":"tutorial/greenfunctions/","page":"GreenFunctions","title":"GreenFunctions","text":"which is zero in this spin-degenerate case","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 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/#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/#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 a GreenSolver, 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\nObservable: a physical observable that can be expressed in terms of a GreenFunction.\nExamples of supported observables include local density of states, current density, transmission probability, conductance and Josephson current","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, inspector = true)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"\"Kane-Mele","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"The inspector = true keyword enables interactive tooltips in the visualization of h that 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 wrap, which makes h periodic along a number of its Bravais vectors, while leaving the rest unbounded.","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"julia> wrap(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 wrap(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 wrapping hoppings, while each colon leaves the lattice unbounded along the corresponding Bravais vector. In a way wrap is dual to supercell, in the sense that the 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. wrap(h, (ϕ₁, :))(ϕ₂) == h(ϕ₁, ϕ₂)","category":"page"},{"location":"tutorial/hamiltonians/","page":"Hamiltonians","title":"Hamiltonians","text":"warning: Caveat of the Bloch-wrap duality\nThe relation wrap(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 rapping hoppings added by wrap are already present in h, as in the case 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 wrap when models are position dependent.","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":"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 several pre-defined eigensolvers. 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\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\nAdditionally, to compute interior eigenvalues, we can use a shift-invert method around energy ϵ0 (uses LinearMaps and a LinearSolve.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\nIf the required packages are not already available, they will be automatically loaded when calling these solvers.\n\nExamples\n\njulia> h = HP.graphene(t0 = 1) |> supercell(10);\n\njulia> spectrum(h, (0,0), ES.ShiftInvert(ES.ArnoldiMethod(nev = 4), 0.0)) |> energies\n4-element Vector{ComplexF64}:\n -0.38196601125010465 + 3.686368662666227e-16im\n -0.6180339887498938 + 6.015655020129746e-17im\n 0.6180339887498927 + 2.6478518218421853e-16im\n 0.38196601125010476 - 1.741261108320361e-16im\n\nSee also\n\n`spectrum`, `bands`\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.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.\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, 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 LatticePresets. 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`\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`\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`\n\n\n\n\n\n","category":"module"},{"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/#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 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 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.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; 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. 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 null self-energy Σᵢⱼ(ω) = 0 on selected sites, which in effect simply amounts to defining a contact on said sites, 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). The positions of the selected sites in h must match, modulo an arbitrary displacement, those of the lead unit cell, after applying transform to the latter. If they don't, 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() |> 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\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.cellsites","page":"API","title":"Quantica.cellsites","text":"cellsites(cell_indices, site_indices)\n\nSimple selector of sites with given site_indices in a given cell at cell_indices. Here, site_indices can be an index, a collection of integers or : (for all sites), and cell_indices should be a collection of L integers, where L is the lattice dimension.\n\nSee also\n\n`siteselector`\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::AbstractHamiltonians...; 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\nExamples\n\njulia> # Building Bernal-stacked bilayer graphene\n\njulia> hbot = HP.graphene(a0 = 1, dim = 3); htop = translate(hbot, (0, 1/√3, 1/√3));\n\njulia> h2 = combine(hbot, htop; coupling = hopping(1, sublats = :B => :C) |> plusadjoint))\n┌ Warning: Renamed repeated sublattice :A to :C\n└ @ Quantica ~/.julia/dev/Quantica/src/types.jl:60\n┌ Warning: Renamed repeated sublattice :B to :D\n└ @ Quantica ~/.julia/dev/Quantica/src/types.jl:60\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)\n2.999999999999999\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(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\nExample\n\njulia> # A semi-infinite 1D lead with a magnetic field `B`\n\njulia> g = LP.square() |> hamiltonian(@hopping((r, dr; B = 0.1) -> cis(B * dr' * SA[r[2],-r[1]]))) |> supercell((1,0), region = r->-2 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\n\nSee also\n\n`greenfunction`, `ldos`, `conductance`, `josephson`, `transmission`\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.greenfunction","page":"API","title":"Quantica.greenfunction","text":"greenfunction(h::Union{AbstractHamiltonian,OpenHamiltonian}, solver::GreenSolver)\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\nIf kernel = missing, efficiently construct diag(g[i, i]). If kernel is a matrix, return tr(g[site, site] * kernel) over each site encoded in i. Note that if there are several orbitals per site, these will have different length (i.e. number of orbitals vs number of sites). See also diagonal.\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 dense and has scalar elements, so that any orbital structure on each site is flattened.\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\nSee also\n\n`GreenSolvers`, `diagonal`, `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 a Hamiltonian or ParametricHamiltonian by applying model to the lattice lat (see onsite, @onsite, hopping and @hopping for details on building tight-binding models).\n\nhamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)\nhamiltonian(h::AbstractHamiltonian, modifiers...; orbitals = 1)\n\nCreate a ParametricHamiltonian where all onsite and hopping terms in model can be parametrically modified through the provided modifiers (see @onsite! and @hopping! for details on defining modifiers).\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 indivisual 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\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\nSee also\n\n`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`\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.josephson","page":"API","title":"Quantica.josephson","text":"josephson(gs::GreenSlice, ωmax; kBT = 0.0, phases = missing, imshift = missing, slope = 1, post = real, atol = 1e-7, quadgk_opts...)\n\nFor a gs = g[i::Integer] slice of the g::GreenFunction of a hybrid junction, build a partially evaluated object J::Integrator representing the equilibrium (static) Josephson current I_J flowing into g through contact i, integrated from -ωmax to ωmax (or from -ωmax to 0 at zero temperature kBT = 0). 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(ω) = (qeh) 2Tr(ΣʳᵢGʳ - GʳΣʳᵢ)τz.\n\nFull evaluation\n\nJ(; params...)\n\nEvaluate the Josephson current I_J for the given g parameters params, if any.\n\nKeywords\n\nkBT : temperature in same energy units as the Hamiltonian\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) 0; 0 cis(ϕ/2)] rotation to the self energy, which is almost free. If missing, a single I_J is returned.\nimshift: if missing the initial and final integration points ± ωmax are shifted by im * sqrt(eps(ωmax)), to avoid the real axis. Otherwise a shift im*imshift is applied (may be zero if ωmax is greater than the bandwidth).\nslope: if non-zero, the integration will be performed along a piecewise-linear path in the complex plane (-ωmax, -ωmax/2 * (1+slope*im), 0, ωmax/2 * (1+slope*im), ωmax), taking advantage of the holomorphic integrand f(ω) j(ω) and the Cauchy Integral Theorem for faster convergence.\npost: function to apply to the result of ∫ dω f(ω) j(ω) to obtain the result, post = real by default.\natol: absolute integration tolerance. The default 1e-7 is chosen to avoid excessive integration times when the current is actually zero.\nquadgk_opts : 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.0005 * SA[0 1; 1 0]) + 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; phases = subdiv(0, pi, 10))\nIntegrator: Complex-plane integrator\n Integration path : (-4.0 + 1.4901161193847656e-8im, -2.0 + 2.000000014901161im, 0.0 + 1.4901161193847656e-8im)\n Integration options : ()\n Integrand: :\n JosephsonDensity{Float64} : Equilibrium (dc) Josephson current observable before integration over energy\n kBT : 0.0\n Contact : 1\n Number of phase shifts : 10\n\njulia> J()\n10-element Vector{Float64}:\n -6.751348391359149e-16\n 0.0016315088241546964\n 0.003213820056117238\n 0.004699191781510955\n 0.0060427526322931946\n 0.0072038354411029185\n 0.008147188939639644\n 0.008844017741703502\n 0.009272686515034255\n -1.7744618723033526e-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...]\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\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 = I)\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 = I)\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 ρᵢ(ω) = -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.\n\nFull evaluation\n\nρω[sites...]\nρs(ω; params...)\n\nGiven a partially evaluated ρω::LocalSpectralDensitySolution or ρs::LocalSpectralDensitySlice, build a vector [ρ₁(ω), ρ₂(ω)...] of fully evaluated local densities of states.\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 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.(g[diagonal(1; kernel = I)](0.2)) ./ π\ntrue\n\nSee also\n\n`greenfunction`, `diagonal`, `current`, `conductance`, `josephson`, `transmission`\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.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.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\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.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.honecycomb() |> hamiltonian(hopping(1)) |> supercell((1,-1), region = r->-2 greenfunction(GS.Schur(boundary = 0));\n\njulia> g0 = LP.honecycomb() |> hamiltonian(hopping(1)) |> supercell(region = r->-2 attach(glead, reverse = true) |> attach(glead) |> greenfunction;\n\njulia> T = transmission(g0[2, 1])\nTransmission: total transmission probability between two different contacts\n From contact : 1\n To contact : 2\n\njulia> T(0.2) # The difference from 3 is due to the automatic `im*sqrt(eps(Float64))` added to `ω`\n2.9999999410323537\n\njulia> T(0.2 + 0.00000000000001im)\n2.999999999999961\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.wrap","page":"API","title":"Quantica.wrap","text":"wrap(h::AbstractHamiltonian, (ϕ₁, ϕ₂,...))\n\nFor an h of lattice dimension L and a set of L Bloch phases ϕ = (ϕ₁, ϕ₂,...), contruct a new zero-dimensional h´::AbstractHamiltonian for all Bravais vectors have been eliminated by wrapping the lattice onto itself along the corresponding Bravais vector. Intercell hoppings along wrapped 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 wrapped, and the resulting h´ will have a finite lattice dimension L´.\n\nCurrying\n\nh |> wrap((ϕ₁, ϕ₂,...))\n\nCurrying syntax equivalent to wrap(h, (ϕ₁, ϕ₂,...)).\n\nExamples\n\njulia> h2D = HP.graphene(); h1D = wrap(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.@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\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 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`\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\nExamples\n\njulia> model = hopping(1); peierls = @hopping!((t, r, dr; A = r -> SA[0,0]) -> t * cis(-dr' * A(r)))\nOnsiteModifier{ParametricFunction{3}}:\n Region : any\n Sublattice pairs : any\n Cell distances : any\n Hopping range : Neighbors(1)\n Reverse hops : false\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`\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\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 Parameters : [:dμ]\n ParametricOnsiteTerm{ParametricFunction{0}}\n Region : any\n Sublattices : B\n Cells : any\n Coefficient : 1\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`\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\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 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`\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) - ldos: computes the local density of states at specific energy and sites - current: computes the local current density along specific directions, and at specific energy and sites - transmission: computes the total transmission between contacts - conductance: computes the differential conductance dIᵢ/dVⱼ between contacts i and j - josephson: 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 ρ = 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 ρ 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> ρ = 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 = ρ, siteradius = ρ, 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 ρ[sites...] produces a vector with the LDOS at sites defined by siteselector(; sites...) (ρ[] 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/#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() |> onsite(4) - hopping(1) |> supercell(region = RP.circle(100) | RP.rectangle((202, 50)) | RP.rectangle((50, 202)))\n\njulia> glead = LP.square() |> onsite(4) - 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 = sum(abs2, g(0.04)[siteselector(), 1], dims = 2);\n\njulia> qplot(hcentral, hide = :hops, siteoutline = 1, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], 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":"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(0, 8, 200);\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> 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\" If 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/#Josephson","page":"Observables","title":"Josephson","text":"","category":"section"},{"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 Parameters : [:B, :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 Parameters : [:t]\n OnsiteTerm{Int64}:\n Region : any\n Sublattices : any\n Cells : any\n Coefficient : 2","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 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.","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, inspector = true)","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, length = npoints) or collect(LinRange(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´ = 1) -> 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/#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 28c56d55..a0a16471 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 f11beccd..581248c9 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 a GreenSolver, 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
      • Observable: a physical observable that can be expressed in terms of a GreenFunction.

        Examples of supported observables include local density of states, current density, transmission probability, conductance and Josephson current

      +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 a GreenSolver, 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
      • Observable: a physical observable that can be expressed in terms of a GreenFunction.

        Examples of supported observables include local density of states, current density, transmission probability, conductance and Josephson current

      diff --git a/dev/tutorial/greenfunctions/index.html b/dev/tutorial/greenfunctions/index.html index a9bdbf33..b9da9b60 100644 --- a/dev/tutorial/greenfunctions/index.html +++ b/dev/tutorial/greenfunctions/index.html @@ -98,4 +98,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 0eee8ba0..71859ebe 100644 --- a/dev/tutorial/hamiltonians/index.html +++ b/dev/tutorial/hamiltonians/index.html @@ -104,4 +104,4 @@ 0.0+0.0im ⋅ ⋅ ⋅ ⋅ 0.0+0.0im ⋅ ⋅ ⋅ ⋅ 0.0+0.0im ⋅ - ⋅ ⋅ ⋅ 0.0+0.0im

      As a consequence, h and supercell(h) represent exactly the same system, with the same observables, but with a different choice of unitcell.

      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 wrap when models are position dependent.

      + ⋅ ⋅ ⋅ 0.0+0.0im

      As a consequence, h and supercell(h) represent exactly the same system, with the same observables, but with a different choice of unitcell.

      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 wrap when models are position dependent.

      diff --git a/dev/tutorial/lattices/index.html b/dev/tutorial/lattices/index.html index 24e6bf33..e6e9db63 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 2fb21b07..ecf6fb8f 100644 --- a/dev/tutorial/models/index.html +++ b/dev/tutorial/models/index.html @@ -81,4 +81,4 @@ Cell distances : any Hopping range : Inf Reverse hops : false - 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 f9dcc46c..324e1d8d 100644 --- a/dev/tutorial/observables/index.html +++ b/dev/tutorial/observables/index.html @@ -33,10 +33,18 @@ julia> qplot(hcentral, hide = :hops, siteoutline = 1, sitecolor = (i, r) -> gx1[i], siteradius = (i, r) -> gx1[i], minmaxsiteradius = (0, 2), sitecolormap = :balance)Green function from right lead

      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

      julia> using ProgressMeter
       
      -julia> T₂₁ = transmission(g[2,1]); T₃₁ = transmission(g[3,1]); ωs = subdiv(0, 4, 200);
      +julia> T₂₁ = transmission(g[2,1]); T₃₁ = transmission(g[3,1]); ωs = subdiv(0, 8, 200);
       
       julia> T₂₁ω = @showprogress [T₂₁(ω) for ω in ωs]; T₃₁ω = @showprogress [T₃₁(ω) for ω in ωs];
      -Progress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:05
      -Progress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:04
      +Progress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:02
      +Progress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:00
       
      -julia> 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
      Total transmission from right contact

      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.

      Total transmission vs transmission probability

      Note 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^2/h$ according to the Landauer formula, $G_j = e^2/h \sum_i T_{ij}(eV)$.

      Conductance

      Josephson

      +julia> 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); fTotal transmission from right contact

      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.

      Total transmission vs transmission probability

      Note 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^2/h$ according to the Landauer formula, $G_j = e^2/h \sum_i T_{ij}(eV)$.

      Conductance

      Local and non-local differential conductance $G_{ij} = dI_i/dV_j$ can be computed with G = conductance(g[i,j]). Calling G(ω) returns the conductance at bias $eV = \omega$ in units of $e^2/h$. Let's look at the local differential conductance into the right contact in the previous example

      julia> G₁₁ = conductance(g[1,1])
      +Conductance{Float64}: Zero-temperature conductance dIᵢ/dVⱼ from contacts i,j, in units of e^2/h
      +  Current contact  : 1
      +  Bias contact     : 1
      +
      +julia> Gω = @showprogress  [G₁₁(ω) for ω in ωs];
      +Progress: 100%|██████████████████████████████████████████████████████████████| Time: 0:01:01
      +
      +julia> f = Figure(); a = Axis(f[1,1], xlabel = "eV/t", ylabel = "G [e²/h]"); lines!(a, ωs, Gω); f
      Local conductance from right contact

      !! warning "Sign of non-local conductance" If 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.

      Josephson

      diff --git a/dev/tutorial/tutorial/index.html b/dev/tutorial/tutorial/index.html index 871fa19a..9139c564 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.