Hamiltonian construction (untested)

This commit is contained in:
ysyapa 2023-08-18 07:04:13 +00:00
parent 56a8808938
commit 5bdf84a0f1
4 changed files with 158 additions and 30 deletions

View File

@ -9,6 +9,9 @@ struct Hamiltonian{T}
K_partial::Matrix{Complex{T}} K_partial::Matrix{Complex{T}}
K_diag::Union{CuTensor{Complex{T}},Nothing} K_diag::Union{CuTensor{Complex{T}},Nothing}
K_mixed::Union{CuTensor{Complex{T}},Nothing} K_mixed::Union{CuTensor{Complex{T}},Nothing}
K_partial_1x::Union{Matrix{Complex{T}},Nothing}
K_partial_1y::Union{Matrix{Complex{T}},Nothing}
K_partial_1z::Union{Matrix{Complex{T}},Nothing}
Vs::Union{Array{Complex{T}},CuArray{Complex{T}}} Vs::Union{Array{Complex{T}},CuArray{Complex{T}}}
hermitian::Bool hermitian::Bool
mode::Hamiltonian_backend mode::Hamiltonian_backend
@ -16,25 +19,27 @@ struct Hamiltonian{T}
function Hamiltonian{T}(s::system{T}, V_twobody::Function, ϕ::Real, n_image::Int, mode::Hamiltonian_backend) where {T<:Float} function Hamiltonian{T}(s::system{T}, V_twobody::Function, ϕ::Real, n_image::Int, mode::Hamiltonian_backend) where {T<:Float}
@assert mode != gpu_cutensor || CUDA.functional() && CUDA.has_cuda() && CUDA.has_cuda_gpu() "CUDA not available" @assert mode != gpu_cutensor || CUDA.functional() && CUDA.has_cuda() && CUDA.has_cuda_gpu() "CUDA not available"
k = -s.N÷2:s.N÷2-1 k = -s.N÷2:s.N÷2-1
Vs = calculate_Vs(s, V_twobody, convert(T, ϕ), n_image)
hermitian = ϕ == 0.0 hermitian = ϕ == 0.0
K_partial = (exp(-im * convert(T, ϕ)) * im / sqrt(2 * s.μ)) .* ∂_1DOF.(Ref(s), k, k') K_partial = (exp(-im * convert(T, ϕ)) * im / sqrt(2 * s.μ)) .* ∂_1DOF.(Ref(s), k, k')
K_diag = nothing K_partial_1x, K_partial_1y, K_partial_1z = sym_reduce(s, K_partial)
K_mixed = nothing Vs = calculate_Vs(s, V_twobody, convert(T, ϕ), n_image)
if mode == gpu_cutensor if mode == gpu_cutensor
K_diag = CuTensor(CuArray(K_partial * K_partial), ['a', 'A']) K_diag = CuTensor(CuArray(K_partial * K_partial), ['a', 'A'])
K_mixed = CuTensor(CuArray(K_partial), ['a', 'A']) * CuTensor(CuArray(K_partial), ['b', 'B']) K_mixed = CuTensor(CuArray(K_partial), ['a', 'A']) * CuTensor(CuArray(K_partial), ['b', 'B'])
Vs = CuArray(Vs) Vs = CuArray(Vs)
else
K_diag = nothing
K_mixed = nothing
end end
return new{T}(s, K_partial, K_diag, K_mixed, Vs, hermitian, mode) return new{T}(s, K_partial, K_diag, K_mixed, K_partial_1x, K_partial_1y, K_partial_1z, Vs, hermitian, mode)
end end
end end
Base.size(H::Hamiltonian, i::Int)::Int = (i == 1 || i == 2) ? H.s.N^(H.s.d * (H.s.n - 1)) : throw(ArgumentError("Hamiltonian only has 2 dimesions")) Base.size(H::Hamiltonian, i::Int)::Int = (i == 1 || i == 2) ? H.s.N^(H.s.d * (H.s.n - 2)) * H.dim1 : throw(ArgumentError("Hamiltonian only has 2 dimesions"))
Base.size(H::Hamiltonian)::Dims{2} = (size(H, 1), size(H, 2)) Base.size(H::Hamiltonian)::Dims{2} = (size(H, 1), size(H, 2))
"Dimensions of a vector to which 'H' can be applied" "Dimensions of a vector to which 'H' can be applied"
vectorDims(H::Hamiltonian)::Dims = tuple(fill(H.s.N, H.s.d * (H.s.n - 1))...) vectorDims(H::Hamiltonian)::Dims = tuple(H.dim1, fill(H.s.N, H.s.d * (H.s.n - 2))...)
"Apply 'H' on 'v' and store the result in 'out' using the 'cpu_tensor' backend" "Apply 'H' on 'v' and store the result in 'out' using the 'cpu_tensor' backend"
function LinearAlgebra.mul!(out::Array{Complex{T}}, H::Hamiltonian{T}, v::Array{Complex{T}})::Array{Complex{T}} where {T<:Float} function LinearAlgebra.mul!(out::Array{Complex{T}}, H::Hamiltonian{T}, v::Array{Complex{T}})::Array{Complex{T}} where {T<:Float}
@ -47,18 +52,23 @@ function LinearAlgebra.mul!(out::Array{Complex{T}}, H::Hamiltonian{T}, v::Array{
for dim = 1:H.s.d for dim = 1:H.s.d
for coord1 = 1:coords for coord1 = 1:coords
for coord2 = 1:coord1 for coord2 = 1:coord1
i1 = which_index(H.s, dim, coord1)
i2 = which_index(H.s, dim, coord2) if coord1 == 1 && coord2 == 1
nconList_1 = [-i1, 1]
nconList_2 = [-i2, 2]
nconList_v = copy(nconList_v_template)
if i1 == i2
nconList_2[1] = 1
else else
nconList_v[i1] = 1 i1 = which_index(H.s, dim, coord1)
i2 = which_index(H.s, dim, coord2)
nconList_1 = [-i1, 1]
nconList_2 = [-i2, 2]
nconList_v = copy(nconList_v_template)
if i1 == i2
nconList_2[1] = 1
else
nconList_v[i1] = 1
end
nconList_v[i2] = 2
v_new = @ncon((H.K_partial, H.K_partial, v), (nconList_1, nconList_2, nconList_v))
end end
nconList_v[i2] = 2
v_new = @ncon((H.K_partial, H.K_partial, v), (nconList_1, nconList_2, nconList_v))
out = axpy!(1, v_new, out) out = axpy!(1, v_new, out)
end end
end end

View File

@ -1,4 +1,7 @@
include("irrep.jl")
Float = Union{Float32,Float64} Float = Union{Float32,Float64}
@enum rep all A1
"A few-body system defined by its physical parameters" "A few-body system defined by its physical parameters"
struct system{T} struct system{T}
@ -8,7 +11,22 @@ struct system{T}
L::T L::T
μ::T μ::T
system{T}(d::Int, n::Int, N::Int, L::Real, μ::Real=0.5) where {T<:Float} = new{T}(d, n, N, convert(T, L), convert(T, μ)) sym::rep
unique_i::Array{Int}
unique_point::Array{Int}
multiplicity::Array{Int}
function system{T}(d::Int, n::Int, N::Int, L::Real, μ::Real=0.5, sym::rep=all) where {T<:Float}
@assert d == 3 "Only supports 3D"
if sym == all
unique_i, unique_point, multiplicity = calculate_all_data(N)
elseif sym == A1
unique_i, unique_point, multiplicity = calculate_A1_data(N)
else
throw(ArgumentError("Symmetry not yet implemented"))
end
return new{T}(d, n, N, convert(T, L), convert(T, μ), sym, unique_i, unique_point, multiplicity)
end
end end
norm_square(x::Array{Int})::Int = sum(x .* x) norm_square(x::Array{Int})::Int = sum(x .* x)
@ -23,18 +41,27 @@ function ∂_1DOF(s::system{T}, k::Int, l::Int)::Complex{T} where {T<:Float}
end end
"Which index (dimension of the multidimensional array) corresponds to spatial dimension 'dim' and particle 'p'?" "Which index (dimension of the multidimensional array) corresponds to spatial dimension 'dim' and particle 'p'?"
which_index(s::system, dim::Int, p::Int)::Int = (dim - 1) * (s.n - 1) + p which_index(s::system, dim::Int, p::Int)::Int = (dim - 1) * (s.n - 2) + p + 1
"Δk (distance in terms of lattice paramter) between two particles along the given dimension"
function get_k(s::system, i::CartesianIndex, dim::Int, p::Int)::Int
if p == 1
s.unique_point[i[1], dim]
else
return i[which_index(s, dim, p)] - s.N ÷ 2 - 1
end
end
"Δk (distance in terms of lattice paramter) between two particles along the given dimension" "Δk (distance in terms of lattice paramter) between two particles along the given dimension"
function get_Δk(s::system, i::CartesianIndex, dim::Int, p1::Int, p2::Int)::Int function get_Δk(s::system, i::CartesianIndex, dim::Int, p1::Int, p2::Int)::Int
if p1 == p2 if p1 == p2
return 0 return 0
elseif p1 == s.n elseif p1 == s.n
return -(i[which_index(s, dim, p2)] - s.N ÷ 2 - 1) return -get_k(s, i, dim, p2)
elseif p2 == s.n elseif p2 == s.n
return i[which_index(s, dim, p1)] - s.N ÷ 2 - 1 return get_k(s, i, dim, p1)
else else
return i[which_index(s, dim, p1)] - i[which_index(s, dim, p2)] return get_k(s, i, dim, p1) - get_k(s, i, dim, p2)
end end
end end
@ -42,7 +69,7 @@ end
function calculate_Vs(s::system{T}, V_twobody::Function, ϕ::T, n_image::Int)::Array{Complex{T}} where {T<:Float} function calculate_Vs(s::system{T}, V_twobody::Function, ϕ::T, n_image::Int)::Array{Complex{T}} where {T<:Float}
coeff² = (exp(im * ϕ) * s.L / s.N)^2 coeff² = (exp(im * ϕ) * s.L / s.N)^2
images = collect.(Iterators.product(fill(-n_image:n_image, s.d)...)) # TODO: Learn how to use tuples instead of vectors images = collect.(Iterators.product(fill(-n_image:n_image, s.d)...)) # TODO: Learn how to use tuples instead of vectors
Vs = zeros(Complex{T}, fill(s.N, s.d * (s.n - 1))...) Vs = zeros(Complex{T}, length(s.unique_i), fill(s.N, s.d * (s.n - 2))...)
Threads.@threads for i in CartesianIndices(Vs) Threads.@threads for i in CartesianIndices(Vs)
for p1 in 1:s.n for p1 in 1:s.n
for p2 in (p1 + 1):s.n for p2 in (p1 + 1):s.n

View File

@ -1,9 +1,18 @@
using DelimitedFiles using DelimitedFiles, LinearAlgebra, StatsBase
rotations = readdlm("rotations.mat", ',', Int, '\n')
rotations = reshape(rotations, (24, 3, 3))
function get_A1_labels(N::Int) function calculate_all_data(N::Int)
rotations = readdlm("rotations.csv", ',', Int, '\n') ks = -N÷2:N÷2-1
lattice = hcat((collect.(Iterators.product(ks, ks, ks)))...)
unique_i = collect(1:N^3)
multiplicity = fill(1, length(unique_i))
unique_point = transpose(lattice)
return unique_i, unique_point, multiplicity
end
function calculate_A1_data(N::Int)
rotations = readdlm("rotations.mat", ',', Int, '\n')
rotations = reshape(rotations, (24, 3, 3)) rotations = reshape(rotations, (24, 3, 3))
ks = -N÷2:N÷2-1 ks = -N÷2:N÷2-1
@ -25,9 +34,42 @@ function get_A1_labels(N::Int)
end end
end end
return labels unique_i = unique(labels)
multiplicity = countmap(labels)
unique_point = transpose(lattice[unique_i, :])
return unique_i, unique_point, multiplicity
end end
function sym_reduce(N::Int, K_full) function sym_reduce(s, K_partial)
I = one(K_partial)
K_partial_x = kron(kron(K_partial, I), I)
K_partial_y = kron(kron(I, K_partial), I)
K_partial_z = kron(kron(I, I), K_partial)
# for s in 1:N^3
# if labels[s] != s
# for mat in (K_partial_x, K_partial_y, K_partial_z)
# mat[labels[s], :] += mat[s, :]
# mat[s, :] = 0
# mat[:, labels[s]] += mat[:, s]
# mat[:, s] = 0
# end
# end
# end
for i in s.unique_i
K_partial_x[i, :] *= s.multiplicity[i]
K_partial_x[:, i] *= s.multiplicity[i]
K_partial_y[i, :] *= s.multiplicity[i]
K_partial_y[:, i] *= s.multiplicity[i]
K_partial_z[i, :] *= s.multiplicity[i]
K_partial_z[:, i] *= s.multiplicity[i]
end
K_partial_x = K_partial_x[s.unique_i, s.unique_i]
K_partial_y = K_partial_y[s.unique_i, s.unique_i]
K_partial_z = K_partial_z[s.unique_i, s.unique_i]
return K_partial_x, K_partial_y, K_partial_z
end end

49
testing-irrep.ipynb Normal file
View File

@ -0,0 +1,49 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"include(\"Hamiltonian.jl\")\n",
"\n",
"println(\"Running with \",Threads.nthreads(),\" thread(s)\")\n",
"\n",
"T=Float32\n",
"\n",
"function V_test(r2)\n",
" return -4*exp(-r2/4)\n",
"end\n",
"\n",
"n = 2\n",
"N = 16\n",
"println(\"\\n$n-body system with N=$N\")\n",
"\n",
"for L::T in 5.0:9.0\n",
" print(\"L=$L\")\n",
" s=system{T}(3,n,N,L,0.5,all)\n",
" @time H=Hamiltonian{T}(s,V_test,0,0,cpu_tensor)\n",
" #evals,_,_ = eig(H,5)\n",
" #println(real.(evals))\n",
"end"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.0",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.0"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}