Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
pablosanjose committed Nov 25, 2024
1 parent 75fd834 commit e726140
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/Quantica.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export sublat, bravais_matrix, lattice, sites, supercell, hamiltonian,
plusadjoint, neighbors, siteselector, hopselector, diagonal, sitepairs,
unflat, torus, transform, translate, combine,
spectrum, energies, states, bands, subdiv,
greenfunction, selfenergy, attach,
greenfunction, selfenergy, attach, matsubara,
plotlattice, plotlattice!, plotbands, plotbands!, qplot, qplot!, qplotdefaults,
conductance, josephson, ldos, current, transmission, densitymatrix,
OrbitalSliceArray, OrbitalSliceVector, OrbitalSliceMatrix, orbaxes, siteindexdict,
Expand Down
19 changes: 19 additions & 0 deletions src/docstrings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2054,6 +2054,13 @@ are passed to the `QuadGK.quadgk` integration routine. See below for additiona `
As above with `ωmin = -ωmax`.
densitymatrix(gs::GreenSlice, matsubara(approximate_half_bandwidth::Real); opts...)
As above, but using a vertical integration path from `µ + 0im` to `µ + Inf*im`. At the
moment, this method does not support finite temperatures. The integral is typically more
efficient if `approximate_half_bandwidth` is approximately the half-bandwidth of the system,
but the result should not depend on this number.
## Full evaluation
ρ(μ = 0, kBT = 0; params...) # where ρ::DensityMatrix
Expand Down Expand Up @@ -2215,6 +2222,18 @@ Return the vertices of the polygonal integration path used to compute `O(args...
"""
path

"""
matsubara(half_bandwdith::Real)
Represent an integration method along a vertical path in the complex-ω plane, from the real
axis to imaginary infinity. This is intended to be used with `densitymatrix`, and currently
only supports zero temperatures.
# See also
`densitymatrix`
"""
matsubara


"""
OrbitalSliceArray <: AbstractArray
Expand Down
138 changes: 97 additions & 41 deletions src/observables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

abstract type IndexableObservable end # any type that can be sliced into (current and ldos)

fermi::C, β = Inf; atol = sqrt(eps(real(C)))) where {C} =
isinf(β) ? ifelse(abs(ω) < atol, C(0.5), ifelse(real(ω) <= 0, C(1), C(0))) : C(1/(exp* ω) + 1))
fermi::C, β = Inf) where {C} =
isinf(β) ? ifelse(real(ω) <= 0, C(1), C(0)) : C(1/(exp* ω) + 1))

normal_size(h::AbstractHamiltonian) = normal_size(blockstructure(h))

Expand Down Expand Up @@ -79,11 +79,9 @@ end

#region ## Constructor ##

function Integrator(result, f, pts; imshift = missing, post = identity, slope = 0, callback = Returns(nothing), quadgk_opts...)
imshift´ = imshift === missing ?
sqrt(eps(promote_type(typeof.(float.(real.(pts)))...))) : float(imshift)
function Integrator(result, f, pts; applyshifts = true, imshift = missing, post = identity, slope = 0, callback = Returns(nothing), quadgk_opts...)
sanitize_integration_points(pts)
pts´ = apply_complex_shifts(pts, imshift´, slope)
pts´ = maybe_apply_complex_shifts(pts, imshift, slope)
quadgk_opts´ = NamedTuple(quadgk_opts)
return Integrator(f, pts´, result, quadgk_opts´, callback, post)
end
Expand All @@ -104,14 +102,14 @@ function sanitize_integration_points(pts)
return pts
end

# If all points are real, apply sawtooth with slope
apply_complex_shifts(pts::NTuple{<:Any,Real}, imshift, slope) =
iszero(slope) ? pts .+ (im * imshift) : triangular_sawtooth(imshift, slope, pts)
apply_complex_shifts(pts::AbstractVector{<:Real}, imshift, slope) =
iszero(slope) ? (pts .+ (im * imshift)) : triangular_sawtooth(imshift, slope, pts)
maybe_apply_complex_shifts(pts, imshift, slope) = pts

# Otherwise do not modify
apply_complex_shifts(pts, imshift, slope) = pts
function maybe_apply_complex_shifts(pts::Union{NTuple{<:Any,Real},AbstractVector{<:Real}}, imshift, slope::Number)
imshift´ = imshift === missing ?
sqrt(eps(promote_type(typeof.(float.(real.(pts)))...))) : float(imshift)
pts´ = iszero(slope) ? (pts .+ (im * imshift´)) : triangular_sawtooth(imshift´, slope, pts)
return pts´
end

triangular_sawtooth(is, sl, ωs::Tuple) = _triangular_sawtooth(is, sl, (), ωs...)
_triangular_sawtooth(is, sl, ::Tuple{}, ω1, ωs...) = _triangular_sawtooth(is, sl, (ω1 + im * is,), ωs...)
Expand Down Expand Up @@ -469,11 +467,13 @@ end
#region

# this produces gs(ω; params...) * f(ω-mu). Use post = gf_to_rho! after integration
struct DensityMatrixIntegrand{G<:GreenSlice,T,O}
struct DensityMatrixIntegrand{G<:GreenSlice,T,O,F1,F2}
gs::G
mu::T
kBT::T
omegamap::O
omegamap::O # to change system parameters for each ω
omega_transform::F1 # to apply to ω at each point
integrand_transform!::F2 # to apply to integrand at each point
end

# Default solver (integration in complex plane)
Expand All @@ -488,6 +488,14 @@ end

#region ## Constructors ##

# default omega_transform, integrand_transform! and omegamap
DensityMatrixIntegrand(gs, mu, kBT, omegamap = identity, omega_transform = identity) =
DensityMatrixIntegrand(gs, mu, kBT, omegamap, omega_transform, identity)

#endregion

#region ## Call ##

# generic fallback (for other solvers)
::DensityMatrix)(mu = 0, kBT = 0; params...) =
ρ.solver(mu, kBT; params...)
Expand All @@ -509,6 +517,49 @@ densitymatrix(s::AppliedGreenSolver, gs::GreenSlice; kw...) =
# default integrator solver
densitymatrix(gs::GreenSlice, ωmax::Number; opts...) = densitymatrix(gs, (-ωmax, ωmax); opts...)

#endregion

#region ## API ##

(gf::DensityMatrixIntegrand)(ω; params...) = copy(call!(gf, ω; params...))

function call!(gf::DensityMatrixIntegrand, ω; params...)
ω´ = gf.omega_transform(ω)
output = call!(gf.gs, ω´; gf.omegamap(ω´)..., params...)
serialize(output) .*= fermi(ω´ - gf.mu, inv(gf.kBT))
gf.integrand_transform!(output)
return output
end

function gf_to_rho!(x::AbstractMatrix)
x .= x .- x'
x .*= -1/(2π*im)
return x
end

# For diagonal indexing
function gf_to_rho!(x::AbstractVector)
x .= x .- conj.(x)
x .*= -1/(2π*im)
return x
end

integrand::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0.0, kBT = 0.0) = integrand.solver(mu, kBT))

path::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0.0, kBT = 0.0) = path.solver(mu, kBT))

temperature(D::DensityMatrixIntegrand) = D.kBT

chemicalpotential(D::DensityMatrixIntegrand) = D.mu

Base.parent::DensityMatrix) = ρ.gs

call!_output::DensityMatrix) = call!_output.gs)

#endregion

#region ## Default integration solver

function densitymatrix(gs::GreenSlice{T}, ωpoints; omegamap = Returns((;)), imshift = missing, atol = 1e-7, opts...) where {T}
# check_nodiag_axes(gs)
result = copy(call!_output(gs))
Expand Down Expand Up @@ -561,42 +612,47 @@ override_path!(override_path, ptsvec, pts) =

#endregion

#region ## API ##
#region ## Alternative integration solvers - Matsubara

(gf::DensityMatrixIntegrand)(ω; params...) = copy(call!(gf, ω; params...))

function call!(gf::DensityMatrixIntegrand, ω; params...)
output = call!(gf.gs, ω; gf.omegamap(ω)..., params...)
serialize(output) .*= fermi- gf.mu, inv(gf.kBT))
return output
struct Matsubara{T<:AbstractFloat}
half_bandwidth::T
end

function gf_to_rho!(x::AbstractMatrix)
x .= x .- x'
x .*= -1/(2π*im)
return x
end
matsubara(h::Real) = Matsubara(float(h))
matsubara(h...) = argerror("Expected matsubara(half_bandwidth::Real)")

# For diagonal indexing
function gf_to_rho!(x::AbstractVector)
x .= x .- conj.(x)
x .*= -1/(2π*im)
return x
function densitymatrix(gs::GreenSlice{T}, c::Matsubara; omegamap = Returns((;)), imshift = missing, atol = 1e-7, opts...) where {T}
result = copy(call!_output(gs))
opts´ = (; imshift, slope = nothing, post = cauchy_post_transform, atol, opts...)
hW = c.half_bandwidth
hW > 0 || argerror("The estimated half-bandwidth for Matsubara integration should be positive, got $hW")
integrand_transform! = cauchy_integrand_tranform(hW)
function ifunc(mu, kBT, override_path)
iszero(kBT) || argerror("The Matsubara integrator currently requires zero temperature, got $kBT")
override_path === missing || argerror("The Matsubara integrator doesn't allow path overrides")
omega_transform = cauchy_omega_tranform(mu, hW)
ρd = DensityMatrixIntegrand(gs, T(mu), zero(T), omegamap, omega_transform, integrand_transform!)
pts = (zero(T), T(Inf))
return Integrator(result, ρd, pts; opts´...)
end
return DensityMatrix(DensityMatrixIntegratorSolver(ifunc), gs)
end

integrand::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0.0, kBT = 0.0) = integrand.solver(mu, kBT))

path::DensityMatrix{<:DensityMatrixIntegratorSolver}, mu = 0.0, kBT = 0.0) = path.solver(mu, kBT))

temperature(D::DensityMatrixIntegrand) = D.kBT

chemicalpotential(D::DensityMatrixIntegrand) = D.mu
cauchy_omega_tranform(mu, hW) = x -> mu + hW * x * im

Base.parent::DensityMatrix) = ρ.gs
cauchy_integrand_tranform(hW) = x -> begin
serialize(x) .*= -im*hW
gf_to_rho!(x)
return x
end

call!_output::DensityMatrix) = call!_output.gs)
function cauchy_post_transform(x)
return x + (I*0.5)
end

#endregion
#endregion


############################################################################################
# josephson
Expand Down

0 comments on commit e726140

Please sign in to comment.