-
-
Notifications
You must be signed in to change notification settings - Fork 360
/
Copy pathsplit_op.jl
146 lines (119 loc) · 4.1 KB
/
split_op.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#------------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
#
#------------------------------------------------------------------------------#
using FFTW
struct Param
xmax::Float64
res::Int64
dt::Float64
timesteps::Int64
dx::Float64
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),
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)),
im_val
)
end
mutable struct Operators
V::Vector{Complex{Float64}}
R::Vector{Complex{Float64}}
K::Vector{Complex{Float64}}
wfc::Vector{Complex{Float64}}
Operators(res) = new(zeros(res),
zeros(res),
zeros(res),
zeros(res))
end
# Function to initialize the wfc and potential
function init(par::Param, voffset::Float64, wfcoffset::Float64)
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.K = exp.(-0.5*par.k.^2*par.dt)
opr.R = exp.(-0.5*opr.V*par.dt)
else
opr.K = exp.(-im*0.5*par.k.^2*par.dt)
opr.R = exp.(-im*0.5*opr.V*par.dt)
end
return opr
end
# Function for the split-operator loop
function split_op!(par::Param, opr::Operators)
for i = 1:par.timesteps
# Half-step in real space
opr.wfc = opr.wfc .* opr.R
# fft to momentum space
opr.wfc = fft(opr.wfc)
# Full step in momentum space
opr.wfc = opr.wfc .* opr.K
# ifft back
opr.wfc = ifft(opr.wfc)
# final half-step in real space
opr.wfc = opr.wfc .* opr.R
# density for plotting and potential
density = abs2.(opr.wfc)
# renormalizing for imaginary time
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(string(i-1), 5, string(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(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()