Skip to content

Commit

Permalink
Merge pull request #7 from krivenko/dev/exact_atomic_ppgf
Browse files Browse the repository at this point in the history
Exact atomic PPGF functionality.
  • Loading branch information
krivenko authored Jul 10, 2024
2 parents 77d61f9 + 9db3f50 commit 8f63ab8
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 26 deletions.
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ makedocs(;
"modules/expansion.md",
"modules/inchworm.md",
"modules/ppgf.md",
"modules/exact_atomic_ppgf.md",
"modules/sector_block_matrix.md",
"modules/spline_gf.md",
"modules/utility.md",
Expand Down
3 changes: 2 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ two-point correlation functions for it.
- [`QInchworm.expansion`](@ref QInchworm.expansion)
- [`QInchworm.inchworm`](@ref QInchworm.inchworm)
- [`QInchworm.ppgf`](@ref QInchworm.ppgf)
- [`QInchworm.exact_atomic_ppgf`](@ref QInchworm.exact_atomic_ppgf)
- [`QInchworm.sector_block_matrix`](@ref QInchworm.sector_block_matrix)
- [`QInchworm.spline_gf`](@ref QInchworm.spline_gf)
- [`QInchworm.utility`](@ref QInchworm.utility)
Expand All @@ -48,4 +49,4 @@ two-point correlation functions for it.
- [`QInchworm.qmc_integrate`](@ref QInchworm.qmc_integrate)
- [`QInchworm.randomization`](@ref QInchworm.randomization)
- [`QInchworm.diagrammatics`](@ref QInchworm.diagrammatics)
- [`QInchworm.topology_eval`](@ref QInchworm.topology_eval)
- [`QInchworm.topology_eval`](@ref QInchworm.topology_eval)
5 changes: 5 additions & 0 deletions docs/src/modules/exact_atomic_ppgf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# [`QInchworm.exact_atomic_ppgf`](@id QInchworm.exact_atomic_ppgf)

```@autodocs
Modules = [QInchworm.exact_atomic_ppgf]
```
1 change: 1 addition & 0 deletions src/QInchworm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ include("mpi.jl")
include("diagrammatics.jl")
include("spline_gf.jl")
include("ppgf.jl")
include("exact_atomic_ppgf.jl")
include("expansion.jl")
include("configuration.jl")
include("qmc_integrate.jl")
Expand Down
158 changes: 158 additions & 0 deletions src/exact_atomic_ppgf.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# QInchworm.jl
#
# Copyright (C) 2021-2024 I. Krivenko, H. U. R. Strand and J. Kleinhenz
#
# QInchworm.jl is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# QInchworm.jl is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# QInchworm.jl. If not, see <http://www.gnu.org/licenses/>.
#
# Authors: Hugo U. R. Strand, Igor Krivenko

"""
Exact atomic pseudo-particle Green's function module enabling exact evaluation of the atomic
propagator ``P_0(z)`` by evaluating the exponential ``P_0(z) = -i e^{-iz \\hat H_{loc}}``.
# Exports
$(EXPORTS)
"""
module exact_atomic_ppgf

using DocStringExtensions

using LinearAlgebra: Diagonal, tr

using Keldysh: BranchPoint, AbstractTimeGF
using KeldyshED; ked = KeldyshED;

import Keldysh: interpolate!
import QInchworm.ppgf: partition_function, atomic_ppgf, density_matrix

export ExactAtomicPPGF, partition_function, atomic_ppgf, density_matrix, interpolate!

"""
$(TYPEDEF)
Exact atomic pseudo-particle Green's function type.
# Fields
$(TYPEDFIELDS)
"""
struct ExactAtomicPPGF <: AbstractTimeGF{ComplexF64, false}
"Inverse temperature"
β::Float64
"Eigenvalues of the atomic Hamiltonian"
E::Array{Float64, 1}
end

"""
$(TYPEDSIGNATURES)
Evaluate atomic propagator at complex contour time `z`.
# Parameters
- `z`: scalar time.
# Returns
- Value of atomic pseudo-particle propagator ``P_0(z)`` as a diagonal matrix
`Diagonal`.
"""
function (P::ExactAtomicPPGF)(z::Number)
return -im * Diagonal(exp.(-im * z * P.E))
end

"""
$(TYPEDSIGNATURES)
Evaluate atomic propagator at the difference between imaginary time branch points.
# Parameters
- `z1`: first branch point.
- `z2`: second branch point.
# Returns
- Value of atomic pseudo-particle propagator ``P_0(z_1 - z_2)`` as a diagonal matrix
`Diagonal`.
"""
function (P::ExactAtomicPPGF)(z1::BranchPoint, z2::BranchPoint)
Δz = z1.val - z2.val
return P(Δz)
end

"""
$(TYPEDSIGNATURES)
In-place evaluation of the atomic propagator at the difference between imaginary time branch
points.
# Parameters
- `x`: Matrix to store the value of the atomic pseudo-particle propagator in.
- `P_0`: Atomic pseudo-particle propagator.
- `z1`: first branch point.
- `z2`: second branch point.
# Returns
- Value of atomic pseudo-particle propagator ``P_0(z_1 - z_2)`` as a diagonal matrix
`Diagonal`.
"""
function interpolate!(x::Matrix{ComplexF64},
P_0::ExactAtomicPPGF,
z1::BranchPoint,
z2::BranchPoint)
Δz = z1.val - z2.val
x[:] = P_0(Δz)
end

"""
$(TYPEDSIGNATURES)
Construct the exact atomic pseudo-particle Green's function.
# Parameters
- `β`: Inverse temperature.
- `ed`: Exact diagonalization structure describing the atomic problem.
"""
function atomic_ppgf::Float64, ed::ked.EDCore)::Vector{ExactAtomicPPGF}
Z = ked.partition_function(ed, β)
λ = log(Z) / β # Pseudo-particle chemical potential (enforcing Tr[i P(β)] = Tr[ρ] = 1)
P = [ ExactAtomicPPGF(β, E .+ λ) for E in energies(ed) ]
return P
end

"""
$(TYPEDSIGNATURES)
Extract the partition function ``Z = \\mathrm{Tr}[i P_0(-i\\beta, 0)]`` from a un-normalized
pseudo-particle Green's function `P_0`.
"""
function partition_function(P_0::Vector{ExactAtomicPPGF})::ComplexF64
return sum(P_0, init=0im) do P_s
im * tr(P_s(-im * P_s.β))
end
end

"""
$(TYPEDSIGNATURES)
Extract the equilibrium density matrix ``\\rho = i P(-i\\beta, 0)`` from a normalized
pseudo-particle Green's function `P`. The density matrix is block-diagonal and is returned
as a vector of blocks.
"""
function density_matrix(P::Vector{ExactAtomicPPGF})::Vector{Matrix{ComplexF64}}
@assert !isempty(P)
return [1im * P_s(-im * P_s.β) for P_s in P]
end

end # module exact_atomic_ppgf
35 changes: 14 additions & 21 deletions src/expansion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ using KeldyshED; ked = KeldyshED; op = KeldyshED.Operators;

using QInchworm.sector_block_matrix: SectorBlockMatrix, operator_to_sector_block_matrix
using QInchworm.ppgf
using QInchworm.exact_atomic_ppgf: atomic_ppgf, ExactAtomicPPGF
using QInchworm.diagrammatics: Topology
using QInchworm.spline_gf: SplineInterpolatedGF
using QInchworm.spline_gf: IncSplineImaginaryTimeGF, extend!
Expand All @@ -44,6 +45,7 @@ const Operator = op.RealOperatorExpr
const AllPPGFSectorTypes = Union{
ppgf.FullTimePPGFSector,
ppgf.ImaginaryTimePPGFSector,
ExactAtomicPPGF,
SplineInterpolatedGF{ppgf.FullTimePPGFSector, ComplexF64, false},
SplineInterpolatedGF{ppgf.ImaginaryTimePPGFSector, ComplexF64, false},
IncSplineImaginaryTimeGF{ComplexF64, false}
Expand All @@ -53,6 +55,7 @@ const AllPPGFSectorTypes = Union{
const AllPPGFTypes = Union{
Vector{ppgf.FullTimePPGFSector},
Vector{ppgf.ImaginaryTimePPGFSector},
Vector{ExactAtomicPPGF},
Vector{SplineInterpolatedGF{ppgf.FullTimePPGFSector, ComplexF64, false}},
Vector{SplineInterpolatedGF{ppgf.ImaginaryTimePPGFSector, ComplexF64, false}},
Vector{IncSplineImaginaryTimeGF{ComplexF64, false}}
Expand Down Expand Up @@ -101,13 +104,13 @@ pseudo-particle expansion problem.
# Fields
$(FIELDS)
"""
struct Expansion{ScalarGF <: kd.AbstractTimeGF{ComplexF64, true}, PPGF <: AllPPGFTypes}
struct Expansion{ScalarGF <: kd.AbstractTimeGF{ComplexF64, true}, PPGF_P0 <: AllPPGFTypes, PPGF_P <: AllPPGFTypes}
"Exact diagonalization solver for the local degrees of freedom"
ed::ked.EDCore
"Non-interacting propagator (pseudo-particle Green's function)"
P0::PPGF
P0::PPGF_P0
"Interacting propagator (pseudo-particle Green's function)"
P::PPGF
P::PPGF_P
"List of pseudo-particle interactions"
pairs::Vector{InteractionPair{ScalarGF}}
"List of hybridization function determinants (not implemented yet)"
Expand Down Expand Up @@ -147,28 +150,18 @@ struct Expansion{ScalarGF <: kd.AbstractTimeGF{ComplexF64, true}, PPGF <: AllPPG
interaction_pairs::Vector{InteractionPair{ScalarGF}};
corr_operators::Vector{Tuple{Operator, Operator}} = Tuple{Operator, Operator}[],
interpolate_ppgf = false) where ScalarGF
P0 = ppgf.atomic_ppgf(grid, ed)
dP0 = ppgf.initial_ppgf_derivative(ed, grid.contour.β)
P = deepcopy(P0)

P0 = atomic_ppgf(grid.contour.β, ed)
P = ppgf.atomic_ppgf(grid, ed)

if interpolate_ppgf

P0_interp = [
IncSplineImaginaryTimeGF(P0_s, dP0_s) for (P0_s, dP0_s) in zip(P0, dP0)
]

dP = ppgf.initial_ppgf_derivative(ed, grid.contour.β)

P_interp = [
IncSplineImaginaryTimeGF(P_s, dP0_s) for (P_s, dP0_s) in zip(P, dP0)
IncSplineImaginaryTimeGF(P_s, dP_s) for (P_s, dP_s) in zip(P, dP)
]

# -- Fill up P0 with all values
for (s, p0_interp) in enumerate(P0_interp)
τ_0 = grid[1]
for τ in grid[2:end]
extend!(p0_interp, P0[s][τ, τ_0])
end
end

P0 = P0_interp
P = P_interp
end

Expand All @@ -189,7 +182,7 @@ struct Expansion{ScalarGF <: kd.AbstractTimeGF{ComplexF64, true}, PPGF <: AllPPG
for s in eachindex(ed.subspaces)
]

return new{ScalarGF, typeof(P0)}(
return new{ScalarGF, typeof(P0), typeof(P)}(
ed,
P0,
P,
Expand Down
8 changes: 4 additions & 4 deletions src/inchworm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,8 @@ function inchworm!(expansion::Expansion,

# Prepare containers for order-resolved contributions to the bold propagator
orders_all = union(orders, orders_bare)
P_orders = Dict(order => kd.zero(expansion.P0) for order in orders_all)
P_orders_std = Dict(order => kd.zero(expansion.P0) for order in orders_all)
P_orders = Dict(order => kd.zero(expansion.P) for order in orders_all)
P_orders_std = Dict(order => kd.zero(expansion.P) for order in orders_all)

# First inchworm step
top_data = TopologiesInputData[]
Expand Down Expand Up @@ -695,8 +695,8 @@ function diff_inchworm!(expansion::Expansion,
end

# Prepare containers for order-resolved contributions to the self-energy
Σ_orders = Dict(order => kd.zero(expansion.P0) for order in orders)
Σ_orders_std = Dict(order => kd.zero(expansion.P0) for order in orders)
Σ_orders = Dict(order => kd.zero(expansion.P) for order in orders)
Σ_orders_std = Dict(order => kd.zero(expansion.P) for order in orders)

# Differential inching
top_data = TopologiesInputData[]
Expand Down
60 changes: 60 additions & 0 deletions test/exact_atomic_ppgf.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# QInchworm.jl
#
# Copyright (C) 2021-2024 I. Krivenko, H. U. R. Strand and J. Kleinhenz
#
# QInchworm.jl is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# QInchworm.jl is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# QInchworm.jl. If not, see <http://www.gnu.org/licenses/>.
#
# Authors: Hugo U. R. Strand, Igor Krivenko

# Test exact atomic pseudo particle Green's function (exact_atomic_ppgf) module
# by comparing with the standard equidistant constructor in the ppgf module.

using Test

using Keldysh; kd = Keldysh
using KeldyshED; ked = KeldyshED; op = KeldyshED.Operators

using QInchworm.ppgf: atomic_ppgf, partition_function
using QInchworm.exact_atomic_ppgf: exact_atomic_ppgf, partition_function

@testset "exact_atomic_ppgf" begin

β = 5.0
= 11
μ = 1.337

H = μ * op.n(1)
soi = ked.Hilbert.SetOfIndices([[1]])
ed = ked.EDCore(H, soi)

P = atomic_ppgf(β, ed)
Z = partition_function(P)
@test Z 1.0

contour = kd.ImaginaryContour=β)
grid = kd.ImaginaryTimeGrid(contour, nτ)
P0 = atomic_ppgf(grid, ed)
Z0 = partition_function(P0)
@test Z == Z0

t0 = grid.points[1].bpoint

for t1 in grid.points
t1 = t1.bpoint
for (p, p0) in zip(P, P0)
@test p(t1, t0) == p0(t1, t0)
end
end

end
Binary file modified test/inchworm.h5
Binary file not shown.
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ include("scrambled_sobol.jl")
include("utility.jl")
include("spline_gf.jl")
include("ppgf.jl")
include("exact_atomic_ppgf.jl")
include("qmc_integrate.jl")
include("nca_equil.jl")
include("diagrammatics.jl")
Expand Down

0 comments on commit 8f63ab8

Please sign in to comment.