Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize AbstractHamiltonian indexing #280

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions src/docstrings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -603,16 +603,24 @@ neighbors
"""
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).
Create an `AbstractHamiltonian` (i.e. an `Hamiltonian` or `ParametricHamiltonian`) by
applying `model` to the lattice `lat` (see `onsite`, `@onsite`, `hopping` and `@hopping` for
details on building parametric and non-parametric tight-binding models).

hamiltonian(lat::Lattice, model, modifiers...; orbitals = 1)
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).
parametrically modified through the provided parametric `modifiers` (see `@onsite!` and
`@hopping!` for details on defining modifiers).

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

Add modifiers to an existing `AbstractHamiltonian`.

hamiltonian(h::ParametricHamiltonian)

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

## Keywords

Expand Down Expand Up @@ -650,9 +658,18 @@ Special syntax equivalent to `h[(0...)]`, which access the fundamental Bloch har
h[i::CellSites, j::CellSites = i]

With `i` and `j` of type `CellSites` and constructed with `sites([cell,] indices)`, return a
sparse matrix block of `h` between the sites with the corresponding `indices` and in the
`SparseMatrixCSC` block of `h` between the sites with the corresponding `indices` and in the
given `cell`s.

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

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

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

## Call syntax

ph(; params...)
Expand Down Expand Up @@ -690,10 +707,22 @@ julia> h((0,0))
⋅ ⋅ 3.0+0.0im 0.0+0.0im
0.0+0.0im 3.0+0.0im ⋅ ⋅
3.0+0.0im 0.0+0.0im ⋅ ⋅

julia> h[sites(1), sites(2)]
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
0.0+0.0im 1.0+0.0im
1.0+0.0im 0.0+0.0im

julia> ph = h |> @hopping!((t; p = 3) -> p*t); ph[region = RP.square(1)]
4×4 OrbitalSliceMatrix{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}:
0.0+0.0im 0.0+0.0im 0.0+0.0im 3.0+0.0im
0.0+0.0im 0.0+0.0im 3.0+0.0im 0.0+0.0im
0.0+0.0im 3.0+0.0im 0.0+0.0im 0.0+0.0im
3.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im
```

# See also
`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`
`lattice`, `onsite`, `hopping`, `@onsite`, `@hopping`, `@onsite!`, `@hopping!`, `ishermitian`, `OrbitalSliceMatrix`
"""
hamiltonian

Expand Down
1 change: 0 additions & 1 deletion src/greenfunction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ Base.getindex(g::GreenFunction; kw...) = g[siteselector(; kw...)]
Base.getindex(g::GreenFunction, kw::NamedTuple) = g[siteselector(; kw...)]

Base.getindex(g::GreenSolution; kw...) = g[getindex(lattice(g); kw...)]
Base.getindex(g::GreenSolution, kw::NamedTuple) = g[getindex(lattice(g); kw...)]

# g[::Integer, ::Integer] and g[:, :] - intra and inter contacts
Base.view(g::GreenSolution, i::CT, j::CT = i) where {CT<:Union{Integer,Colon}} =
Expand Down
29 changes: 26 additions & 3 deletions src/hamiltonian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -406,9 +406,11 @@ call!_output(p::ParametricHamiltonian) = call!_output(hamiltonian(p))
#endregion

############################################################################################
# indexing into AbstractHamiltonian (harmonic extraction) - see also slices.jl
# indexing into AbstractHamiltonian - see also slices.jl
#region

# Extraction of Harmonics

Base.getindex(h::AbstractHamiltonian, dn::Union{Tuple,Integer,SVector,AbstractVector}) =
flat(h[hybrid(dn)])

Expand Down Expand Up @@ -441,10 +443,31 @@ function Base.isassigned(h::AbstractHamiltonian{<:Any,<:Any,L}, dn::SVector{L,In
return false
end

# SiteSelector indexing - replicates GreenSolution indexing - see GreenFunctions.jl

Base.getindex(h::ParametricHamiltonian; kw...) = getindex(call!(h); kw...)
Base.getindex(h::Hamiltonian; kw...) = h[siteselector(; kw...)]

# conversion down to CellOrbitals. See sites_to_orbs in slices.jl
Base.getindex(h::ParametricHamiltonian, i, j) = getindex(call!(h), i, j)
Base.getindex(h::Hamiltonian, i, j) = getindex(h, sites_to_orbs(i, h), sites_to_orbs(j, h))
# we need AbstractHamiltonian here to avoid ambiguities with dn above
Base.getindex(h::AbstractHamiltonian, i) = (i´ = sites_to_orbs(i, h); getindex(h, i´, i´))

# wrapped matrix for end user consumption
Base.getindex(h::Hamiltonian, i::OrbitalSliceGrouped, j::OrbitalSliceGrouped) =
OrbitalSliceMatrix(
mortar((h[si, sj] for si in cellsdict(i), sj in cellsdict(j))),
(i, j))

Base.getindex(h::Hamiltonian, i::AnyOrbitalSlice, j::AnyOrbitalSlice) =
mortar((h[si, sj] for si in cellsdict(i), sj in cellsdict(j)))

Base.getindex(h::Hamiltonian, i::AnyOrbitalSlice, j::AnyCellOrbitals) =
mortar((h[si, sj] for si in cellsdict(i), sj in (j,)))

Base.getindex(h::AbstractHamiltonian, i::AnyCellSites, j::AnyCellSites = i) =
hamiltonian(h)[sites_to_orbs(i, h), sites_to_orbs(j, h)]
Base.getindex(h::Hamiltonian, i::AnyCellOrbitals, j::AnyOrbitalSlice) =
mortar((h[si, sj] for si in (i,), sj in cellsdict(j)))

function Base.getindex(h::Hamiltonian{T}, i::AnyCellOrbitals, j::AnyCellOrbitals) where {T}
dn = cell(i) - cell(j)
Expand Down
7 changes: 4 additions & 3 deletions src/observables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ end
############################################################################################
# ldos: local spectral density
# d = ldos(::GreenSolution; kernel = I) -> d[sites...]::Vector
# d = ldos(::GreenSlice; kernel = I) -> d(ω; params...)::Vector
# d = ldos(::GreenSlice; kernel = I) -> d(ω; params...)::Vector
# Here ldos is given as Tr(ρᵢᵢ * kernel) where ρᵢᵢ is the spectral function at site i
# Here is the generic fallback that uses G. Any more specialized methods need to be added
# to each GreenSolver
Expand Down Expand Up @@ -260,8 +260,9 @@ end

function current_matrix(gω, ls, d)
h = hamiltonian(parent(gω))
# see slices.jl for this form of getindex
current = h[ls, (hij, cij) -> maybe_project(apply_charge_current(hij, cij, d), d.direction)]
# see slices.jl for unflat_getindex
current = unflat_sparse_slice(h, ls, ls,
(hij, cij) -> maybe_project(apply_charge_current(hij, cij, d), d.direction))
return current
end

Expand Down
23 changes: 10 additions & 13 deletions src/slices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,30 +137,28 @@ end
#endregion

############################################################################################
# slice of Hamiltonian h[latslice] - returns a SparseMatrix{B,Int}
# Elements::B can be transformed by `post(hij, (ci, cj))` using h[latslice; post]
# Here ci and cj are single-site CellSite for h
# unflat_sparse_slice: slice of Hamiltonian h[latslice] - returns a SparseMatrix{B,Int}
# This is a more efficient slice builder than mortar, but does not flatten B
# Elements::B can be transformed by `post(hij, (ci, cj))` with `h[latslice, latslice, post]`
# Here ci and cj are single-site `CellSite` for h
# ParametricHamiltonian deliberately not supported, as the output is not updatable
#region

## disabled this method because h[] is too similar to h[()], and becomes confusing
# Base.getindex(h::Hamiltonian; post = (hij, cij) -> hij, kw...) = h[getindex(lattice(h); kw...), post]

function Base.getindex(h::Hamiltonian, ls::LatticeSlice, post = (hij, cij) -> hij)
function unflat_sparse_slice(h::Hamiltonian, lsrows::LS, lscols::LS = lsrows, post = (hij, cij) -> hij) where {LS<:LatticeSlice}
# @assert lattice(h) === lattice(ls) # TODO: fails upon plotting a current density (see tutorial)
cszero = zerocellsites(h, 1)
cszero = zerocellsites(h, 1) # like `sites(1)`, but with explicit cell
B = typeof(post(zero(blocktype(h)), (cszero, cszero)))
ncols = nrows = length(ls)
nrows, ncols = length(lsrows), length(lscols)
builder = CSC{B}(ncols)
hars = harmonics(h)
for colcs in cellsites(ls)
for colcs in cellsites(lscols)
colcell = cell(colcs)
colsite = siteindices(colcs)
for har in hars
rowcell = colcell + dcell(har)
rowsubcell = findsubcell(rowcell, ls)
rowsubcell = findsubcell(rowcell, lsrows)
rowsubcell === nothing && continue
rowoffset = offsets(ls, rowcell)
rowoffset = offsets(lsrows, rowcell)
rowsubcellinds = siteindices(rowsubcell)
# rowsubcellinds are the site indices in original unitcell for subcell = rowcell
# rowoffset is the latslice site offset for the rowsubcellinds sites
Expand All @@ -185,7 +183,6 @@ function Base.getindex(h::Hamiltonian, ls::LatticeSlice, post = (hij, cij) -> hi
return sparse(builder, nrows, ncols)
end


#endregion

############################################################################################
Expand Down
14 changes: 11 additions & 3 deletions test/test_hamiltonian.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Quantica: Hamiltonian, ParametricHamiltonian, BarebonesOperator,
using Quantica: Hamiltonian, ParametricHamiltonian, BarebonesOperator, OrbitalSliceMatrix, SparseMatrixCSC,
sites, nsites, nonsites, nhoppings, coordination, flat, hybrid, transform!, nnz, nonzeros

@testset "basic hamiltonians" begin
Expand Down Expand Up @@ -479,7 +479,15 @@ end
end

@testset "hamiltonian indexing" begin
h = HP.graphene(orbitals = (2, 1), a0 = 1) |> @hopping!((t; p = 0) -> p*t)
@test size(h[sites(1), sites(2)]) == (2, 1)
h = LP.honeycomb() |> hamiltonian(hopping(I), orbitals = (2, 1)) |> @hopping!((t; p = 1) -> p*t)
m = h[sites(1), sites(2)]
@test m isa SparseMatrixCSC
@test m == SA[1; 0;;]
@test iszero(h[sites(1), sites(SA[2,3], 2)])
m = h[cells = 1]
@test m isa OrbitalSliceMatrix
@test m == SA[0 0 1; 0 0 0; 1 0 0]
m = h[sites(2), (; cells = 1)]
@test m isa SparseMatrixCSC
@test m == SA[1 0 0]
end
Loading