Skip to content

Split op updates #249

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

Merged
merged 10 commits into from
Jul 28, 2018
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
18 changes: 18 additions & 0 deletions contents/quantum_systems/code/julia/energy.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# We are calculating the energy to check <Psi|H|Psi>
function calculate_energy(wfc, H_k, H_r, dx)
# Creating momentum and conjugate wavefunctions
wfc_k = fft(wfc_r)
wfc_c = conj(wfc_r)

# Finding the momentum and real-space energy terms
energy_k = wfc_c.*ifft((H_k) .* wfc_k)
energy_r = wfc_c.* H_r .* wfc_r

# Integrating over all space
energy_final = 0
for i = 1:length(energy_k)
energy_final += real(energy_k[i] + energy_r[i])
end

return energy_final*dx
end
195 changes: 173 additions & 22 deletions contents/quantum_systems/quantum_systems.md

Large diffs are not rendered by default.

Binary file added contents/quantum_systems/res/gaussian.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
108 changes: 86 additions & 22 deletions contents/split-operator_method/code/julia/split_op.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using Plots
pyplot()
#------------split_op.jl-------------------------------------------------------#
#
# Plotting: to plot individual timesteps, use gnuplot like so:
# p "output00000.dat" u 1:2 w l
# rep "output00000.dat" u 1:3 w l
#
#------------------------------------------------------------------------------#

# struct to hold all parameters for simulation
struct Param
xmax::Float64
res::Int64
Expand All @@ -11,34 +15,48 @@ struct Param
x::Vector{Float64}
dk::Float64
k::Vector{Float64}
im_time::Bool

Param() = new(10.0, 512, 0.05, 1000, 2 * 10.0/512,
Vector{Float64}(-10.0 + 10.0/512 : 20.0/512 : 10.0),
pi / 10.0,
Vector{Float64}(vcat(0:512/2 - 1, -512/2 : -1) * pi/10.0))
Param(xmax::Float64, res::Int64, dt::Float64, timesteps::Int64) = new(
pi / 10.0,
Vector{Float64}(vcat(0:512/2 - 1, -512/2 : -1) * pi/10.0),
false)
Param(xmax::Float64, res::Int64, dt::Float64, timesteps::Int64,
im_val::Bool) = new(
xmax, res, dt, timesteps,
2*xmax/res, Vector{Float64}(-xmax+xmax/res:2*xmax/res:xmax),
pi/xmax, Vector{Float64}(vcat(0:res/2-1, -res/2:-1)*pi/xmax)
pi/xmax, Vector{Float64}(vcat(0:res/2-1, -res/2:-1)*pi/(xmax)),
im_val
)
end

# struct to hold all operators
mutable struct Operators
V::Vector{Complex{Float64}}
PE::Vector{Complex{Float64}}
KE::Vector{Complex{Float64}}
wfc::Vector{Complex{Float64}}

Operators(res) = new(Vector{Complex{Float64}}(res),
Vector{Complex{Float64}}(res),
Vector{Complex{Float64}}(res),
Vector{Complex{Float64}}(res))
end

# Function to initialize the wfc and potential
function init(par::Param, voffset::Float64, wfcoffset::Float64)
V = 0.5 * (par.x - voffset).^2
wfc = 3 * exp.(-(par.x - wfcoffset).^2/2)
PE = exp.(-0.5*im*V*par.dt)
KE = exp.(-0.5*im*par.k.^2*par.dt)
opr = Operators(length(par.x))
opr.V = 0.5 * (par.x - voffset).^2
opr.wfc = exp.(-(par.x - wfcoffset).^2/2)
if (par.im_time)
opr. = exp.(-0.5*par.k.^2*par.dt)
opr.PE = exp.(-0.5*opr.V*par.dt)
else
opr. = exp.(-im*0.5*par.k.^2*par.dt)
opr.PE = exp.(-im*0.5*opr.V*par.dt)
end

opr = Operators(V, PE, KE, wfc)
return opr
end

# Function for the split-operator loop
Expand All @@ -48,32 +66,78 @@ function split_op(par::Param, opr::Operators)
# Half-step in real space
opr.wfc = opr.wfc .* opr.PE

# fft to phase space
# fft to momentum space
opr.wfc = fft(opr.wfc)

# Full step in phase space
opr.wfc = opr.wfc .* opr.KE
# Full step in momentum space
opr.wfc = opr.wfc .* opr.

# ifft back
opr.wfc = ifft(opr.wfc)

# final half-step in real space
opr.wfc = opr.wfc .* opr.PE

# plotting density and potential
# density for plotting and potential
density = abs2.(opr.wfc)

plot([density, real(opr.V)])
savefig("density" * string(lpad(i, 5, 0)) * ".png")
println(i)
# renormalizing for imaginary time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to renormalize at every time step? I can't quite remember.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I saw later you commented on this. Basically if you don't renormalize the values all fly to 0, right?

if (par.im_time)
renorm_factor = sum(density) * par.dx

for j = 1:length(opr.wfc)
opr.wfc[j] /= sqrt(renorm_factor)
end
end

# Outputting data to file. Plotting can also be done in a similar way
# This is set to output exactly 100 files, no matter how many timesteps
if ((i-1) % div(par.timesteps, 100) == 0)
outfile = open("output" *string(lpad(i-1, 5, 0))* ".dat","w")

# Outputting for gnuplot. Any plotter will do.
for j = 1:length(density)
write(outfile, string(par.x[j]) * "\t"
* string(density[j]) * "\t"
* string(real(opr.V[j])) * "\n")
end

close(outfile)
println("Outputting step: ", i)
end
end
end

# We are calculating the energy to check <Psi|H|Psi>
function calculate_energy(par, opr)
# Creating real, momentum, and conjugate wavefunctions
wfc_r = opr.wfc
wfc_k = fft(wfc_r)
wfc_c = conj(wfc_r)

# Finding the momentum and real-space energy terms
energy_k = 0.5*wfc_c.*ifft((par.k.^2) .* wfc_k)
energy_r = wfc_c.*opr.V .* wfc_r

# Integrating over all space
energy_final = 0
for i = 1:length(energy_k)
energy_final += real(energy_k[i] + energy_r[i])
end

return energy_final*par.dx
end

# main function
function main()
par = Param(10.0, 512, 0.05, 1000)
opr = init(par, 0.0, 1.0)
par = Param(5.0, 256, 0.05, 100, true)

# Starting wavefunction slightly offset so we can see it change
opr = init(par, 0.0, -1.00)
split_op(par, opr)

energy = calculate_energy(par, opr)
println("Energy is: ", energy)
end

main()
Binary file added contents/split-operator_method/res/Psi_t.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added contents/split-operator_method/res/Psi_tdt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added contents/split-operator_method/res/real_time.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added contents/split-operator_method/res/real_time.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading