Skip to content

Commit dc72b2e

Browse files
committed
WIP
fixing tests fixing tests fixing tests test fixes add and fix more tests more tests docs coverage fix tests add tests revert inhomogeneous slice behavior fix for CellOrbitals(:) slicing don't allow CellOrbitals{L,Colon} reach slicers comment test fix generalize API
1 parent d586cb0 commit dc72b2e

14 files changed

+475
-315
lines changed

docs/src/tutorial/observables.md

+42-51
Original file line numberDiff line numberDiff line change
@@ -38,57 +38,61 @@ Note that `d[sites...]` produces a vector with the LDOS at sites defined by `sit
3838
We can also compute the convolution of the density of states with the Fermi distribution `f(ω)=1/(exp((ω-μ)/kBT) + 1)`, which yields the density matrix in thermal equilibrium, at a given temperature `kBT` and chemical potential `μ`. This is computed with `ρ = densitymatrix(gs, (ωmin, ωmax))`. Here `gs = g[sites...]` is a `GreenSlice`, and `(ωmin, ωmax)` are integration bounds (they should span the full bandwidth of the system). Then, `ρ(µ, kBT = 0; params...)` will yield a matrix over the selected `sites` for a set of model `params`.
3939
```julia
4040
julia> ρ = densitymatrix(g[region = RP.circle(1)], (-0.1, 8.1))
41-
DensityMatrix: density matrix on specified sites using solver of type DensityMatrixIntegratorSolver
41+
DensityMatrix{DensityMatrixIntegratorSolver}: density matrix on specified sites
4242

4343
julia> @time ρ(4)
44-
6.150548 seconds (57.84 k allocations: 5.670 GiB, 1.12% gc time)
45-
5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
46-
0.5+0.0im -7.34893e-10-3.94035e-15im 0.204478+1.9366e-14im -7.34889e-10-1.44892e-15im -5.70089e-10+5.48867e-15im
47-
-7.34893e-10+3.94035e-15im 0.5+0.0im 0.200693-2.6646e-14im -5.70089e-10-1.95251e-15im -7.34891e-10-2.13804e-15im
48-
0.204478-1.9366e-14im 0.200693+2.6646e-14im 0.5+0.0im 0.200693+3.55692e-14im 0.204779-4.27255e-14im
49-
-7.34889e-10+1.44892e-15im -5.70089e-10+1.95251e-15im 0.200693-3.55692e-14im 0.5+0.0im -7.34885e-10-3.49861e-15im
50-
-5.70089e-10-5.48867e-15im -7.34891e-10+2.13804e-15im 0.204779+4.27255e-14im -7.34885e-10+3.49861e-15im 0.5+0.0im
44+
4.594645 seconds (111.82 k allocations: 4.890 GiB, 2.81% gc time, 0.86% compilation time)
45+
5×5 OrbitalSliceMatrix{ComplexF64,Array}:
46+
0.5+0.0im -7.35075e-10+3.40256e-15im 0.204478+4.46023e-14im -7.35077e-10-1.13342e-15im -5.70426e-10-2.22213e-15im
47+
-7.35075e-10-3.40256e-15im 0.5+0.0im 0.200693-4.46528e-14im -5.70431e-10+3.53853e-15im -7.35092e-10-4.07992e-16im
48+
0.204478-4.46023e-14im 0.200693+4.46528e-14im 0.5+0.0im 0.200693+6.7793e-14im 0.204779-6.78156e-14im
49+
-7.35077e-10+1.13342e-15im -5.70431e-10-3.53853e-15im 0.200693-6.7793e-14im 0.5+0.0im -7.351e-10+2.04708e-15im
50+
-5.70426e-10+2.22213e-15im -7.35092e-10+4.07992e-16im 0.204779+6.78156e-14im -7.351e-10-2.04708e-15im 0.5+0.0im
5151
```
5252

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

5555
The default algorithm used here is slow, as it relies on numerical integration in the complex plane. Some GreenSolvers have more efficient implementations. If they exist, they can be accessed by omitting the `(ωmin, ωmax)` argument. For example, using `GS.Spectrum`:
5656
```julia
5757
julia> @time g = h |> greenfunction(GS.Spectrum());
58-
37.638522 seconds (105 allocations: 2.744 GiB, 0.79% gc time)
58+
18.249136 seconds (75 allocations: 1.567 GiB, 0.67% gc time)
5959

6060
julia> ρ = densitymatrix(g[region = RP.circle(1)])
61-
DensityMatrix: density matrix on specified sites with solver of type DensityMatrixSpectrumSolver
61+
DensityMatrix{DensityMatrixSpectrumSolver}: density matrix on specified sites
62+
63+
julia> @time ρ(4) # second-run timing
64+
0.029662 seconds (7 allocations: 688 bytes)
65+
5×5 OrbitalSliceMatrix{ComplexF64,Array}:
66+
0.5+0.0im -6.6187e-16+0.0im 0.204478+0.0im 2.49658e-15+0.0im -2.6846e-16+0.0im
67+
-6.6187e-16+0.0im 0.5+0.0im 0.200693+0.0im -2.01174e-15+0.0im 1.2853e-15+0.0im
68+
0.204478+0.0im 0.200693+0.0im 0.5+0.0im 0.200693+0.0im 0.204779+0.0im
69+
2.49658e-15+0.0im -2.01174e-15+0.0im 0.200693+0.0im 0.5+0.0im 1.58804e-15+0.0im
70+
-2.6846e-16+0.0im 1.2853e-15+0.0im 0.204779+0.0im 1.58804e-15+0.0im 0.5+0.0im
6271

63-
julia> @time ρ(4)
64-
0.001659 seconds (9 allocations: 430.906 KiB)
65-
5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
66-
0.5+0.0im -2.21437e-15+0.0im 0.204478+0.0im 2.67668e-15+0.0im 3.49438e-16+0.0im
67-
-2.21437e-15+0.0im 0.5+0.0im 0.200693+0.0im -1.40057e-15+0.0im -2.92995e-15+0.0im
68-
0.204478+0.0im 0.200693+0.0im 0.5+0.0im 0.200693+0.0im 0.204779+0.0im
69-
2.67668e-15+0.0im -1.40057e-15+0.0im 0.200693+0.0im 0.5+0.0im 1.81626e-15+0.0im
70-
3.49438e-16+0.0im -2.92995e-15+0.0im 0.204779+0.0im 1.81626e-15+0.0im 0.5+0.0im
7172
```
7273

7374
Note, however, that the computation of `g` is much slower in this case, due to the need of a full diagonalization. A better algorithm choice in this case is `GS.KPM`. It requires, however, that we define the region for the density matrix beforehand, as a `nothing` contact.
7475
```julia
7576
julia> @time g = h |> attach(nothing, region = RP.circle(1)) |> greenfunction(GS.KPM(order = 10000, bandrange = (0,8)));
76-
Computing moments: 100%|█████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01
77-
2.065083 seconds (31.29 k allocations: 11.763 MiB)
77+
Computing moments: 100%|███████████████████████████████████████████████████████████████████████████████████████| Time: 0:00:01
78+
1.360412 seconds (51.17 k allocations: 11.710 MiB)
7879

7980
julia> ρ = densitymatrix(g[1])
80-
DensityMatrix: density matrix on specified sites with solver of type DensityMatrixKPMSolver
81+
DensityMatrix{DensityMatrixKPMSolver}: density matrix on specified sites
8182

8283
julia> @time ρ(4)
83-
0.006580 seconds (3 allocations: 1.156 KiB)
84-
5×5 OrbitalSliceMatrix{ComplexF64,Matrix{ComplexF64}}:
84+
0.004024 seconds (3 allocations: 688 bytes)
85+
5×5 OrbitalSliceMatrix{ComplexF64,Array}:
8586
0.5+0.0im 2.15097e-17+0.0im 0.20456+0.0im 2.15097e-17+0.0im 3.9251e-17+0.0im
8687
2.15097e-17+0.0im 0.5+0.0im 0.200631+0.0im 1.05873e-16+0.0im 1.70531e-18+0.0im
8788
0.20456+0.0im 0.200631+0.0im 0.5+0.0im 0.200631+0.0im 0.20482+0.0im
8889
2.15097e-17+0.0im 1.05873e-16+0.0im 0.200631+0.0im 0.5+0.0im 1.70531e-18+0.0im
8990
3.9251e-17+0.0im 1.70531e-18+0.0im 0.20482+0.0im 1.70531e-18+0.0im 0.5+0.0im
9091
```
9192

93+
!!! note "Alternative integration paths"
94+
The integration algorithm allows many different integration paths that can be adjusted to each problem, see the `Paths` docstring. Another versatile choice is `Paths.radial(ωrate, ϕ)`. This one is called with `ϕ = π/4` when doing `ρ = densitymatrix(gs::GreenSlice, ωrate::Number)`. In the example above this is slightly faster than the `(ωmin, ωmax)` choice, which resorts to `Paths.sawtooth(ωmin, ωmax)`.
95+
9296
## Current
9397

9498
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
@@ -238,14 +242,7 @@ GreenFunction{Float64,2,0}: Green function of a Hamiltonian{Float64,2,0}
238242
Coordination : 3.7448
239243

240244
julia> J = josephson(g[1], 4.1)
241-
Integrator: Complex-plane integrator
242-
Integration path : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)
243-
Integration options : (atol = 1.0e-7,)
244-
Integrand: :
245-
JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy
246-
kBT : 0.0
247-
Contact : 1
248-
Number of phase shifts : 0
245+
Josephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact
249246

250247
julia> qplot(g, children = (; sitecolor = :blue))
251248
```
@@ -257,37 +254,31 @@ In this case we have chosen to introduce the superconducting leads with a model
257254
corresponding to a BCS bulk, but any other self-energy form could be used. We have introduced the phase difference (`phase`) as a model parameter. We can now evaluate the zero-temperature Josephson current simply with
258255
```julia
259256
julia> J(phase = 0)
260-
-1.974396994480587e-16
257+
1.992660837638158e-12
261258

262259
julia> J(phase = 0.2)
263-
0.004617597139699372
260+
0.0046175971391935605
264261
```
265262
Note that finite temperatures can be taken using the `kBT` keyword argument for `josephson`, see docstring for details.
266263

267264
One is often interested in the critical current, which is the maximum of the Josephson current over all phase differences. Quantica.jl can compute the integral over a collection of phase differences simultaneously, which is more efficient that computing them one by one. This is done with
268265
```julia
269266
julia> φs = subdiv(0, pi, 11); J = josephson(g[1], 4.1; phases = φs)
270-
Integration path : (-4.1 + 1.4901161193847656e-8im, -2.05 + 2.050000014901161im, 0.0 + 1.4901161193847656e-8im)
271-
Integration options : (atol = 1.0e-7,)
272-
Integrand: :
273-
JosephsonIntegrand{Float64} : Equilibrium (dc) Josephson current observable before integration over energy
274-
kBT : 0.0
275-
Contact : 1
276-
Number of phase shifts : 11
267+
Josephson{JosephsonIntegratorSolver}: equilibrium Josephson current at a specific contact
277268

278269
julia>= J()
279270
11-element Vector{Float64}:
280-
1.868862401627357e-14
281-
0.007231421775452674
282-
0.014242855188877
283-
0.02081870760779799
284-
0.026752065104401878
285-
0.031847203848574666
286-
0.0359131410974842
287-
0.03871895510547465
288-
0.039762442694035505
289-
0.03680096751905469
290-
2.7677727119798235e-14
271+
-6.361223111882911e-13
272+
0.007231421776215144
273+
0.01424285518831463
274+
0.020818707606469377
275+
0.026752065101976884
276+
0.031847203846513975
277+
0.035913141096514584
278+
0.038718955102068034
279+
0.03976244268586444
280+
0.036800967573567184
281+
-1.437196514806921e-12
291282

292283
julia> f = Figure(); a = Axis(f[1,1], xlabel = "φ", ylabel = "I [e/h]"); lines!(a, φs, Iφ); scatter!(a, φs, Iφ); f
293284
```

src/docstrings.jl

+63-50
Original file line numberDiff line numberDiff line change
@@ -2050,15 +2050,18 @@ true if `gs` contains user-defined contacts created using `attach(model)` with g
20502050
ω-dependent models, but note that Quantica will not check for analyticity. Keywords
20512051
`quadgk_opts` are passed to the `QuadGK.quadgk` integration routine.
20522052
2053-
densitymatrix(gs::GreenSlice, ωscale::Real; opts..., quadgk_opts...)
2053+
densitymatrix(gs::GreenSlice, ωscale::Real; kw...)
20542054
2055-
As above with `path = Paths.vertical(ωscale)`, which computes the density matrix by
2056-
integrating the Green function along a quarter circle from `ω = -Inf` to `ω = µ + im*Inf`,
2057-
and then back along a vertical path `ω = µ + im*ωscale*x` from `x = Inf` to `x = 0`. Here
2058-
`µ` is the chemical potential and `ωscale` should be some typical energy scale in the system
2059-
(the integration time may depend on `ωscale`, but not the result). This vertical integration
2060-
path approach is performant but, currently it does not support finite temperatures, unlike
2061-
other `AbstractIntegrationPath`s like `Paths.sawtooth`.
2055+
As above with `path = Paths.radial(ωscale, π/4)`, which computes the density matrix by
2056+
integrating the Green function from `ω = -Inf` to `ω = Inf` along a `ϕ = π/4` radial complex
2057+
path, see `Paths` for details. Here `ωscale` should correspond to some typical energy scale
2058+
in the system, which dictates the speed at which we integrate the radial paths (the
2059+
integration runtime may depend on `ωscale`, but not the result).
2060+
2061+
densitymatrix(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)
2062+
2063+
As above, but with a `path = Paths.sawtooth(ωs)`, which uses a sawtooth-shaped path touching
2064+
points `ωs` on the real axes. Ideally, these values should span the full system bandwidth.
20622065
20632066
## Full evaluation
20642067
@@ -2068,9 +2071,6 @@ Evaluate the density matrix at chemical potential `μ` and temperature `kBT` (in
20682071
units as the Hamiltonian) for the given `g` parameters `params`, if any. The result is given
20692072
as an `OrbitalSliceMatrix`, see its docstring for further details.
20702073
2071-
If the generic integration algorithm is used with complex `ωpoints`, the following form is
2072-
also available:
2073-
20742074
## Algorithms and keywords
20752075
20762076
The generic integration algorithm allows for the following `opts` (see also `josephson`):
@@ -2122,13 +2122,16 @@ GʳΣʳᵢ)τz]``. Here `f(ω)` is the Fermi function with `µ = 0`.
21222122
21232123
josephson(gs::GreenSlice, ωscale::Real; kw...)
21242124
2125-
As above, but with `path = Paths.vertical(ωscale)`, which computes josephson current by
2126-
performing the above integral along a quarter circle from `ω = -Inf` to `ω = im*Inf`, and
2127-
then back along a vertical path `ω = im*ωscale*x` from `x = Inf` to `x = 0`. Here `ωscale`
2128-
should be some typical energy scale in the system, like the superconducting gap (the
2129-
integration time may depend on `ωscale`, but not the result). This vertical integration path
2130-
approach is performant but, currently it does not support finite temperatures, unlike other
2131-
`AbstractIntegrationPath`s like `Paths.sawtooth`.
2125+
As above, but with `path = Paths.radial(ωscale, π/4)`, which computes josephson current by
2126+
integrating the Green function from `ω = -Inf` to `ω = Inf` along a `ϕ = π/4` radial complex
2127+
path, see `Paths` for details. Here `ωscale` should be some typical energy scale in the
2128+
system, like the superconducting gap (the integration time may depend on `ωscale`, but not
2129+
the result).
2130+
2131+
josephson(gs::GreenSlice, ωs::NTuple{N,Real}; kw...)
2132+
2133+
As above, but with a `path = Paths.sawtooth(ωs)`, which uses a sawtooth-shaped path touching
2134+
points `ωs` on the real axes. Ideally, these values should span the full system bandwidth.
21322135
21332136
## Full evaluation
21342137
@@ -2155,21 +2158,21 @@ julia> glead = LP.square() |> hamiltonian(@onsite((; ω = 0) -> 0.0005 * SA[0 1;
21552158
21562159
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;
21572160
2158-
julia> J = josephson(g0[1], 4; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))
2161+
julia> J = josephson(g0[1], 0.0005; omegamap = ω -> (;ω), phases = subdiv(0, pi, 10))
21592162
Josephson: equilibrium Josephson current at a specific contact using solver of type JosephsonIntegratorSolver
21602163
21612164
julia> J(0.0)
21622165
10-element Vector{Float64}:
2163-
7.060440509787806e-18
2164-
0.0008178484258721882
2165-
0.0016108816082772972
2166-
0.002355033150366814
2167-
0.0030277117620820513
2168-
0.003608482493380227
2169-
0.004079679643085058
2170-
0.004426918320990192
2171-
0.004639358112465513
2172-
2.2618383948099795e-12
2166+
1.0130103834038537e-15
2167+
0.0008178802022977883
2168+
0.0016109471548779466
2169+
0.0023551370133118215
2170+
0.0030278625151304614
2171+
0.003608696305848759
2172+
0.00407998998248311
2173+
0.0044274100715435295
2174+
0.004640372460465891
2175+
5.179773035314182e-12
21732176
```
21742177
21752178
# See also
@@ -2178,59 +2181,69 @@ julia> J(0.0)
21782181
josephson
21792182

21802183
"""
2181-
Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0)
2184+
Quantica.integrand(J::Josephson{<:JosephsonIntegratorSolver}, kBT = 0; params...)
21822185
2183-
Return the complex integrand `d::JosephsonIntegrand` whose integral over frequency yields the
2184-
Josephson current, `J(kBT) = Re(∫dω d(ω))`. To evaluate the `d` for a
2185-
given `ω` and parameters, use `d(ω; params...)`, or `call!(d, ω; params...)` for its
2186+
Return the complex integrand `d::JosephsonIntegrand` whose integral over frequency yields
2187+
the Josephson current, `J(kBT; params...) = Re(∫dx d(x; params...))`, where `ω(x) =
2188+
Quantica.point(x, d)` is a path parametrization over real variable `x` . To evaluate the `d`
2189+
for a given `x` and parameters, use `d(x; params...)`, or `call!(d, x; params...)` for its
21862190
mutating (non-allocating) version.
21872191
2188-
Quantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0)
2192+
Quantica.integrand(ρ::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0, kBT = 0; params...)
21892193
2190-
Like above for the density matrix `ρ(mu, kBT)`, with `d::DensityMatrixIntegrand`, so that
2191-
`ρ(mu, kBT) = -mat_imag(∫dω d(ω))/π`, and `mat_imag(GF::Matrix) = (GF - GF')/2im`.
2194+
Like above for the density matrix `ρ`, with `d::DensityMatrixIntegrand`, so that `ρ(mu, kBT;
2195+
params...) = -mat_imag(∫dω d(ω; params...))/π`, and `mat_imag(GF::Matrix) = (GF - GF')/2im`.
21922196
21932197
"""
21942198
integrand
21952199

21962200
"""
2197-
Quantica.path(O::Josephson, args...)
2198-
Quantica.path(O::DensityMatrix, args...)
2201+
Quantica.points(O::Josephson, args...)
2202+
Quantica.points(O::DensityMatrix, args...)
21992203
2200-
Return the vertices of the polygonal integration path used to compute `O(args...)`.
2204+
Return the vertices of the integration path used to compute `O(args...)`.
22012205
"""
2202-
path
2206+
points
22032207

22042208
"""
22052209
Paths
22062210
22072211
A Quantica submodule that contains representations of different integration paths in the
2208-
complex-ω plane. Available paths are:
2212+
complex-ω plane for integrals of the form `∫f(ω)g(ω)dω`, where `f(ω)` is the Fermi
2213+
distribution at chemical potential `µ` and temperature `kBT`. Available paths are:
22092214
2210-
Paths.vertical(ωscale::Real)
2215+
Paths.radial(ωscale::Real, ϕ)
22112216
2212-
A vertical path from a point `µ` on the real axis to `µ + Inf*im`. `ωscale` defines the rate at which the integration variable `x` sweeps this ω path, i.e. `ω = µ+im*ωscale*x`.
2217+
A four-segment path from `ω = -Inf` to `ω = Inf`. The path first ascends along an arc of
2218+
angle `ϕ` (with `0 <= ϕ < π/2`) and infinite radius. It then converges along a straight line
2219+
in the second `ω-µ` quadrant to the chemical potential origin `ω = µ`. Finally it performs
2220+
the mirror-symmetric itinerary in the first `ω-µ` quadrant, ending on the real axis at `ω =
2221+
Inf`. The radial segments are traversed at a rate dictated by `ωscale`, that should
2222+
represent some relevant energy scale in the system for optimal convergence of integrals. At
2223+
zero temperature `kBT = 0`, the two last segments don't contribute and are elided.
22132224
2214-
Paths.sawtooth(ωpoints; slope = 1)
2225+
Paths.sawtooth(ωpoints...; slope = 1, imshift = true)
22152226
22162227
A path connecting all points in the `ωpoints` collection (should all be real), but departing
22172228
between each two into the complex plane and back with the given `slope`, forming a sawtooth
22182229
path. Note that an extra point `µ` is added to the collection, where `µ` is the chemical
2219-
potential. This path allows finite temperature integrals
2230+
potential, and the `real(ω)>µ` segments are elided at zero temperatures. If `imshift = true`
2231+
all `ωpoints` (of type `T<:Real`) are shifted by `sqrt(eps(T))` to avoid the real axis.
22202232
2221-
Paths.sawtooth(ωmax::Real; slope = 1)
2233+
Paths.sawtooth(ωmax::Real; kw...)
22222234
22232235
As above with `ωpoints = (-ωmax, ωmax)`.
22242236
2225-
Paths.polygon(ωpoints)
2237+
Paths.polygon(ωpoints...)
22262238
2227-
A ageneral polygonal path connecting `ωpoints`, which can be any collection of real or
2239+
A general polygonal path connecting `ωpoints`, which can be any collection of real or
22282240
complex numbers
22292241
22302242
Paths.polygon(ωfunc::Function)
22312243
2232-
A ageneral polygonal path connecting `ωpoints = ωfunc(µ, kBT)`. This is useful when the
2233-
desired integration path depends on the chemical potential `µ` or temperature `kBT`.
2244+
A ageneral polygonal path connecting `ωpoints = ωfunc(µ, kBT; params...)`. This is useful
2245+
when the desired integration path depends on the chemical potential `µ`, temperature
2246+
`kBT` or other system parameters `params`.
22342247
22352248
# See also
22362249
`densitymatrix`, `josephson`

0 commit comments

Comments
 (0)