aboutsummaryrefslogtreecommitdiff
path: root/t/old/t.jl
diff options
context:
space:
mode:
Diffstat (limited to 't/old/t.jl')
-rw-r--r--t/old/t.jl755
1 files changed, 755 insertions, 0 deletions
diff --git a/t/old/t.jl b/t/old/t.jl
new file mode 100644
index 0000000..6a06777
--- /dev/null
+++ b/t/old/t.jl
@@ -0,0 +1,755 @@
+# molecular dynamics 2d.
+
+# usage:
+# at the end of this script, under the header "DEMOS",
+# you'll see some functions which implement demos from GN chapter 9.
+# simply load the script in your development environment
+# (I strongly recommend not using jupiter)
+# and in the console/REPL run
+# demo_0()
+# etc.
+
+# demos 0,1,3 can optionally make an animated gif
+# if you call it with the optional argument demo_3(gif=1)
+
+# lmk if this script is giving you grief or if you find any bugs
+# kian@brown.edu
+
+using Statistics
+using StatsPlots
+
+mutable struct ParticleSystem
+ N::Int64# number of particles
+ L::Float64# square box side length
+ T₀::Float64# initial temperature
+ t::Float64# system time
+ dt::Float64# time step
+ state::Vector{Float64}# state space array
+ steps::Int64# number of steps
+ sampleInterval::Int64# interval for sampling data
+ timeData::Vector{Float64}# array of sampled time points
+ energyData::Vector{Float64}# array of sampled energy values
+ tempData::Vector{Float64}# array of sampled temperature values
+ tempAccumulator::Float64# temperature accumulator
+ squareTempAccumulator::Float64# T^2 accumulator
+ virialAccumulator::Float64# virial accumulator
+ xData::Vector{Vector{Float64}} # array of sampled position data
+ vData::Vector{Vector{Float64}} # array of sampled velocity data
+ forceType::String# force
+end
+
+function ParticleSystem(N::Int64 = 64, L::Float64 = 10.0, T₀::Float64 = 1.0)
+ t = 0.0
+ dt = 0.001
+ state = zeros(4N) # state space array, [x1,y1,x2,y2,...,vx1,vy1,...]
+ steps = 0
+ timeData = Float64[]
+ energyData = Float64[]
+ sampleInterval = 100
+ tempData = Float64[]
+ tempAccumulator = 0.0
+ squareTempAccumulator = 0.0
+ virialAccumulator = 0.0
+ xData = Vector{Float64}[]
+ vData = Vector{Float64}[]
+ forceType = "lennardJones"
+
+ return ParticleSystem(
+ N,
+ L,
+ T₀,
+ t,
+ dt,
+ state,
+ steps,
+ sampleInterval,
+ timeData,
+ energyData,
+ tempData,
+ tempAccumulator,
+ squareTempAccumulator,
+ virialAccumulator,
+ xData,
+ vData,
+ forceType,
+ )
+end
+
+# some useful "views" of the state array
+# (read the performance tips chapter of the julia manual)
+@views positions(state) = state[1:Int64(length(state) / 2)]
+@views velocities(state) = state[(Int64(length(state) / 2)+1):end]
+@views xcomponent(vector) = vector[1:2:end]
+@views ycomponent(vector) = vector[2:2:end]
+@views particle(n, vector) = [vector[2n-1], vector[2n]]
+
+# INITIALIZATION
+################################################################################
+
+function set_random_positions!(sys::ParticleSystem)
+ println("\tposition configuration: random")
+ positions(sys.state) .= rand(2 * sys.N) .* sys.L
+ cool!(sys)
+end
+
+function set_square_lattice_positions!(sys::ParticleSystem)
+ println("\tposition configuration: square lattice")
+
+ n = Int64(floor(sqrt(sys.N))) # num lattice points per axis
+ latticeSpacing = sys.L / n
+
+ if sys.N != n^2
+ println("\t\toops... your chosen N=$(sys.N) is not a square number")
+ println("\t\t-> resetting N to $(n^2).")
+ sys.N = n^2
+ sys.state = zeros(4 * sys.N)
+ end
+
+ for i in 0:(n-1)
+ for j in 0:(n-1)
+ sys.state[2*(i*n+j)+1] = (i + 0.5) * latticeSpacing
+ sys.state[2*(i*n+j)+2] = (j + 0.5) * latticeSpacing
+ end
+ end
+end
+
+function set_triangular_lattice_positions!(sys::ParticleSystem)
+end
+
+function add_position_jitter!(sys::ParticleSystem, jitter::Float64 = 0.5)
+ println("\tadding a wee bit of random jitter to particle positions...")
+
+ for i ∈ 1:length(positions(sys.state))
+ sys.state[i] += rand() - jitter
+ end
+end
+
+function set_random_velocities!(sys::ParticleSystem)
+ println("\tvelocity configuration: random")
+
+ velocities(sys.state) .= rand(2 * sys.N) .- 0.5
+ zero_total_momentum!(sys)
+ velocities(sys.state) .*= sqrt(sys.T₀ / temperature(sys))
+end
+
+function zero_total_momentum!(sys::ParticleSystem)
+ xcomponent(velocities(sys.state)) .-=
+ mean(xcomponent(velocities(sys.state)))
+ ycomponent(velocities(sys.state)) .-=
+ mean(ycomponent(velocities(sys.state)))
+end
+
+
+# FORCES / POTENTIALS
+################################################################################
+
+function force(sys::ParticleSystem)
+ if sys.forceType == "lennardJones"
+ force, virial = lennard_jones_force(sys)
+ elseif sys.forceType == "powerLaw"
+ force, virial = power_law_force(sys)
+ end
+
+ sys.virialAccumulator += virial
+
+ return force
+end
+
+# the minimum image approximation
+# (periodic boundary conditions)
+function minimum_image(xij::Float64, L::Float64)
+ if xij > (L / 2)
+ xij -= L
+ elseif xij < -(L / 2)
+ xij += L
+ end
+ return xij
+end
+
+function lennard_jones_force(sys::ParticleSystem)
+ x = xcomponent(positions(sys.state))
+ y = ycomponent(positions(sys.state))
+ virial = 0.0
+ force = zeros(2 * sys.N)
+
+ Threads.@threads for i ∈ 1:(sys.N-1)
+ for j ∈ (i+1):sys.N
+ dx = minimum_image(x[i] - x[j], sys.L)
+ dy = minimum_image(y[i] - y[j], sys.L)
+
+ r2inv = 1.0 / (dx^2 + dy^2)
+ f = 48.0 * r2inv^7 - 24.0 * r2inv^4
+ fx = dx * f
+ fy = dy * f
+
+ force[2*i-1] += fx
+ force[2*i] += fy
+ force[2*j-1] -= fx
+ force[2*j] -= fy
+
+ virial += fx * dx + fy * dy
+ end
+ end
+
+ return force, 0.5 * virial
+end
+
+function lennard_jones_potential(sys::ParticleSystem)
+ x = xcomponent(positions(sys.state))
+ y = ycomponent(positions(sys.state))
+ U = 0.0
+
+ Threads.@threads for i in 1:(sys.N-1)
+ for j in (i+1):sys.N
+ dx = minimum_image(x[i] - x[j], sys.L)
+ dy = minimum_image(y[i] - y[j], sys.L)
+
+ r2inv = 1.0 / (dx^2 + dy^2)
+ U += r2inv^6 - r2inv^3
+ end
+ end
+ return 4.0 * U
+end
+
+function power_law_force(sys::ParticleSystem)
+end
+
+function power_law_potential(sys::ParticleSystem)
+end
+
+# TIME EVOLUTION
+################################################################################
+
+function keep_particles_in_box!(sys::ParticleSystem)
+ for i in 1:(2*sys.N)
+ if positions(sys.state)[i] > sys.L
+ positions(sys.state)[i] -= sys.L
+ elseif positions(sys.state)[i] < 0.0
+ positions(sys.state)[i] += sys.L
+ end
+ end
+
+ # # another way of doing this: use the ternary operator
+ # for i in 1:(2 * sys.N)
+ # positions(sys.state)[i] < 0.0 ?
+ # positions(sys.state)[i] % sys.L + sys.L :
+ # positions(sys.state)[i] % sys.L
+ # end
+end
+
+function verlet_step!(sys::ParticleSystem)
+ # compute acceleration at current time
+ acceleration = force(sys)
+
+ # compute positions at t + dt
+ positions(sys.state) .+=
+ velocities(sys.state) .* sys.dt .+
+ 0.5 .* acceleration .* (sys.dt)^2
+
+ # enforce boundary conditions
+ # (basically check if any particles left the box and put them back)
+ # see function implementation for deets
+ keep_particles_in_box!(sys)
+
+ # compute velocities at t + dt
+ velocities(sys.state) .+=
+ 0.5 * sys.dt .* (acceleration + force(sys))
+end
+
+function evolve!(sys::ParticleSystem, runtime::Float64 = 10.0)
+ numsteps = Int64(abs(runtime / sys.dt) + 1)
+
+ print_evolution_message(runtime, numsteps)
+
+ @time for step in 1:numsteps
+ verlet_step!(sys)
+ zero_total_momentum!(sys)
+
+ if (step % sys.sampleInterval == 1)
+ push!(sys.timeData, sys.t)
+ push!(sys.energyData, energy(sys))
+ push!(sys.xData, positions(sys.state))
+ push!(sys.vData, velocities(sys.state))
+
+ T = temperature(sys)
+ push!(sys.tempData, T)
+ sys.tempAccumulator += T
+ sys.squareTempAccumulator += T^2
+ end
+
+ sys.t += sys.dt
+ sys.steps += 1
+ end
+ println("done.")
+end
+
+function reverse_time!(sys)
+ sys.dt *= -1
+ println("\ntime reversed! dt = $(sys.dt)")
+end
+
+function cool!(sys::ParticleSystem, cooltime::Float64 = 1.0)
+ numsteps = Int64(cooltime / sys.dt)
+ for step in 1:numsteps
+ verlet_step!(sys)
+ velocities(sys.state) .*= (1.0 - sys.dt)
+ end
+ reset_statistics!(sys)
+end
+
+# MEASUREMENTS
+################################################################################
+
+function kinetic_energy(sys::ParticleSystem)
+ return 0.5 * sum(velocities(sys.state) .* velocities(sys.state))
+end
+
+function potential_energy(sys::ParticleSystem)
+ return lennard_jones_potential(sys)
+end
+
+function temperature(sys::ParticleSystem)
+ return kinetic_energy(sys) / sys.N
+end
+
+function energy(sys::ParticleSystem)
+ return potential_energy(sys) + kinetic_energy(sys)
+end
+
+# STATISTICS
+################################################################################
+
+function reset_statistics!(sys::ParticleSystem)
+ sys.steps = 0
+ sys.tempAccumulator = 0.0
+ sys.squareTempAccumulator = 0.0
+ sys.virialAccumulator = 0.0
+ sys.xData = []
+ sys.vData = []
+end
+
+function mean_temperature(sys::ParticleSystem)
+ return sys.tempAccumulator / sys.steps
+end
+
+function mean_square_temperature(sys::ParticleSystem)
+ return sys.squareTempAccumulator / sys.steps
+end
+
+function mean_pressure(sys::ParticleSystem)
+ # factor of half because force is calculated twice each step
+ meanVirial = 0.5 * sys.virialAccumulator / sys.steps
+ return 1.0 + 0.5 * meanVirial / (sys.N * mean_temperature(sys))
+end
+
+function heat_capacity(sys::ParticleSystem)
+ meanTemperature = mean_temperature(sys)
+ meanSquareTemperature = mean_square_temperature(sys)
+ σ2 = meanSquareTemperature - meanTemperature^2
+ denom = 1.0 - σ2 * sys.N / meanTemperature^2
+ return sys.N / denom
+end
+
+function mean_energy(sys::ParticleSystem)
+ return mean(sys.energyData)
+end
+
+function std_energy(sys::ParticleSystem)
+ return std(sys.energyData)
+end
+
+# MATH / ADDITIONAL FUNCTIONS
+################################################################################
+
+function dot(v1::Vector{Float64}, v2::Vector{Float64})
+ return sum(v1 .* v2)
+end
+
+# GRAPHS
+################################################################################
+
+function initialize_plot()
+ plot(
+ size = (800, 800),
+ titlefontsize = 12,
+ guidefontsize = 12,
+ )
+end
+
+function plot_positions_t(sys::ParticleSystem, t::Int64)
+ initialize_plot()
+ for n ∈ 1:sys.N
+ scatter!(
+ [sys.xData[t][2n-1]],
+ [sys.xData[t][2n]],
+ markersize = 4.0,
+ markercolor = n,
+ markerstrokewidth = 0.4,
+ grid = true,
+ framestyle = :box,
+ legend = false,
+ )
+ end
+end
+
+function animate(sys::ParticleSystem, interval::Int64 = 1)
+ println("\ngenerating gif...")
+
+ scatter!()
+ animation = @animate for t in 1:length(sys.xData)
+ scatter()
+ for n ∈ 1:sys.N
+ scatter!(
+ [sys.xData[t][2n-1]],
+ [sys.xData[t][2n]],
+ #markersize = 4.0,
+ markercolor = n,
+ #markerstrokewidth = 0.4,
+ grid = true,
+ framestyle = :box,
+ legend = false,
+ )
+ end
+ xlims!(0, sys.L)
+ ylims!(0, sys.L)
+ xlabel!("x")
+ ylabel!("y")
+ end every interval
+
+ gif(animation, "./animation.gif")
+ println("done.")
+end
+
+function plot_positions(sys::ParticleSystem)
+ initialize_plot()
+ for n ∈ 1:sys.N
+ scatter!(
+ [xcomponent(positions(sys.state))[n]],
+ [ycomponent(positions(sys.state))[n]],
+ markersize = 4.0,
+ markercolor = n,
+ markerstrokewidth = 0.4,
+ grid = true,
+ framestyle = :box,
+ legend = false,
+ )
+ end
+ xlims!(0, sys.L)
+ ylims!(0, sys.L)
+ xlabel!("x")
+ ylabel!("y")
+ title!("positions at t=$(round(sys.t, digits=4))")
+end
+
+function plot_trajectories(sys::ParticleSystem, particles::Vector{Int64} = [1])
+ initialize_plot()
+ for n ∈ 1:sys.N
+ scatter!(
+ [xcomponent(positions(sys.state))[n]],
+ [ycomponent(positions(sys.state))[n]],
+ markersize = 4.0,
+ markercolor = n,
+ markerstrokewidth = 0.4,
+ grid = true,
+ framestyle = :box,
+ legend = false,
+ )
+ end
+
+ for n in collect(particles)
+ xdata = [sys.xData[i][2n-1] for i in 1:length(sys.xData)]
+ ydata = [sys.xData[i][2n] for i in 1:length(sys.xData)]
+
+ # plot trajectory line for nth particle
+ scatter!(
+ xdata,
+ ydata,
+ color = n,
+ #markerstrokewidth = 0,
+ markerstrokecolor = n,
+ markersize = 0.7,
+ markeralpha = 0.5,
+ label = false,
+ widen = false,
+ )
+
+ # plot initial position for nth particle
+ scatter!(
+ [sys.xData[1][2n-1]],
+ [sys.xData[1][2n]],
+ markersize = 4.0,
+ markercolor = n,
+ markerstrokewidth = 0.4,
+ markeralpha = 0.3,
+ #label = "pcl. $n @t=t₀",
+ widen = false,
+ )
+
+ # plot final position for nth particle
+ scatter!(
+ [sys.xData[end][2n-1]],
+ [sys.xData[end][2n]],
+ markersize = 4.0,
+ markercolor = n,
+ markerstrokewidth = 0.4,
+ markeralpha = 1.0,
+ #label = "pcl $n @t=t",
+ widen = false,
+ )
+ end
+ title!("positions & trajectories at time t=$(round(sys.t, digits=2))")
+ plot!()
+end
+
+function plot_temperature(sys::ParticleSystem)
+ initialize_plot()
+ plot!(
+ sys.timeData,
+ sys.tempData,
+ #widen = true,
+ )
+ ylims!(
+ mean(sys.tempData) - std(sys.tempData) * 20,
+ mean(sys.tempData) + std(sys.tempData) * 20,
+ )
+ xlabel!("t")
+ ylabel!("T(t)")
+ title!("temperature vs time")
+
+end
+
+function plot_energy(sys::ParticleSystem, ylimit::Float64 = 1.0)
+ initialize_plot()
+ plot!(
+ sys.timeData,
+ sys.energyData,
+ #widen = true,
+ )
+ ylims!(
+ #ylimit * (mean(sys.energyData) - 1),
+ #ylimit * (mean(sys.energyData) + 1)
+ mean(sys.energyData) - std(sys.energyData) * 10,
+ mean(sys.energyData) + std(sys.energyData) * 10,
+ )
+ xlabel!("t")
+ ylabel!("E(t)")
+ title!("energy vs time")
+end
+
+function plot_speed_distribution(sys::ParticleSystem, numSamples::Int64 = 5)
+ initialize_plot()
+
+ numDataPoints = Int64(length(sys.vData))
+ interval = Int64(floor(numDataPoints / numSamples))
+
+ samples = collect(1:interval:numDataPoints)
+ for s in samples
+ speed = sqrt.(
+ xcomponent(sys.vData[s]) .^ 2 .*
+ ycomponent(sys.vData[s]) .^ 2
+ )
+ density!(
+ sys.vData[s],
+ normalize = :pdf,
+ label = "t = $(round(sys.timeData[s], digits=2))",
+ )
+ end
+ xlabel!("speed")
+ title!("speed distribution")
+end
+
+# CONSOLE PRINT DATA
+################################################################################
+
+function print_hello()
+ println("\nmolecular dynamics!")
+ println("number of threads: ", Threads.nthreads())
+end
+
+function print_bonjour()
+ println("\nbonjour")
+end
+
+function print_system_parameters(sys::ParticleSystem)
+ println("\nsystem parameters:")
+ println("\tN = $(sys.N) (number of particles)")
+ println("\tL = $(sys.L) (side length of square box)")
+ println("\tDT = $(sys.dt) (time step)")
+end
+
+function print_system_data(sys::ParticleSystem)
+ println("\nsystem data at time t=$(round(sys.t, digits=4))")
+
+ if sys.steps == 0
+ println("\ttemperature: $(temperature(sys))")
+ println("\tenergy: $(energy(sys))")
+ else
+ println("\tsteps evolved: $(sys.steps)")
+ println("\ttemperature: $(temperature(sys))")
+ println("\tenergy: $(energy(sys))")
+ println("\tmean energy: $(mean_energy(sys))")
+ println("\tstd energy: $(std_energy(sys))")
+ println("\theat capacity: $(heat_capacity(sys))")
+ println("\tPV/NkT: $(mean_pressure(sys))")
+ end
+end
+
+function print_evolution_message(runtime, numsteps)
+ println("\nevolving...")
+end
+
+# DEMOS
+################################################################################
+
+
+# DEMO 0: APPROACH TO EQUILIBRIUM
+function demo_0(; gif = 0)
+ println("\nDEMO 0: APPROACH TO EQUILIBRIUM")
+ println("----------------------------------------")
+
+ sys = ParticleSystem(64, 120.0, 1.0)
+ print_system_parameters(sys)
+
+ set_square_lattice_positions!(sys)
+ set_random_velocities!(sys)
+ print_system_data(sys)
+ p1 = plot_positions(sys)
+
+ evolve!(sys, 20.0)
+ print_system_data(sys)
+
+ p2 = plot_trajectories(sys, collect(1:64))
+ p3 = plot_energy(sys)
+ p4 = plot_temperature(sys)
+
+ # make gif
+ if gif == 1
+ animate(sys, 1)
+ end
+
+ plot(
+ p1, p2, p3, p4,
+ layout = grid(2, 2, heights = [0.7, 0.3]),
+ size = (1280, 720),
+ )
+end
+
+# DEMO 1: TIME REVERSAL TEST
+function demo_1(; gif = 0)
+ println("\nDEMO 1: TIME REVERSAL TEST")
+ println("----------------------------------------")
+
+ sys = ParticleSystem(64, 120.0, 1.0)
+ print_system_parameters(sys)
+
+ set_square_lattice_positions!(sys)
+ set_random_velocities!(sys)
+ print_system_data(sys)
+ p1 = plot_positions(sys)
+
+ evolve!(sys, 50.0)
+ #p2 = plot_trajectories(sys, collect(1:64))
+ p2 = plot_positions(sys)
+
+ reverse_time!(sys)
+ evolve!(sys, 50.0)
+ print_system_data(sys)
+ #p3 = plot_trajectories(sys, collect(1:64))
+ p3 = plot_positions(sys)
+
+ # make gif
+ if gif == 1
+ animate(sys, 4)
+ end
+
+ plot(
+ p1, p2, p3,
+ layout = (1, 3),
+ size = (1200, 400),
+ )
+end
+
+# DEMO 2: SPEED DISTRIBUTION
+function demo_2()
+ println("\nDEMO 2: SPEED DISTRIBUTION")
+ println("----------------------------------------")
+
+ sys = ParticleSystem[]
+
+ # array for speed distribution plots
+ ps = Plots.Plot{Plots.GRBackend}[]
+
+ # array for trajectory plots
+ pt = Plots.Plot{Plots.GRBackend}[]
+
+ # initialize three systems with different initial conditions
+ # but same KE and PE, evolve, and save plots
+ for i ∈ 1:3
+ push!(sys, ParticleSystem(64, 120.0, 1.0))
+
+ println("\nSYSTEM $i")
+ print_system_parameters(sys[i])
+
+ set_square_lattice_positions!(sys[i])
+ add_position_jitter!(sys[i])
+ set_random_velocities!(sys[i])
+ print_system_data(sys[i])
+
+ evolve!(sys[i], 40.0)
+ print_system_data(sys[i])
+ push!(ps, plot_speed_distribution(sys[i], 5))
+ push!(pt, plot_trajectories(sys[i], collect(1:64)))
+ end
+
+
+ # plot speed distribution and trajectory plots
+ plot(
+ ps[1], ps[2], ps[3],
+ pt[1], pt[2], pt[3],
+ layout = (2, 3),
+ size = (1920, 1080),
+ )
+end
+
+# DEMO 3: MELTING TRANSITION
+function demo_3(; gif = 0)
+ println("\nDEMO 3: MELTING TRANSITION")
+ println("----------------------------------------")
+
+ # initialize system of particles on square lattice with zero velocity
+ sys = ParticleSystem(100, 10.0, 5.0)
+ set_square_lattice_positions!(sys)
+ print_system_data(sys)
+ p1 = plot_positions(sys)
+
+ # evolve the system and watch them "crystallize"
+ # into a triangular lattice formation
+ evolve!(sys, 20.0)
+ print_system_data(sys)
+ p2 = plot_trajectories(sys, collect(1:100))
+
+ # now, increase the temperature of the system by giving the particles
+ # some velocity. evolve the system and plot the trajectories.
+ set_random_velocities!(sys)
+ evolve!(sys, 60.0)
+ print_system_data(sys)
+ p3 = plot_trajectories(sys, collect(1:100))
+
+ # some more plots
+ p4 = plot_energy(sys, 0.0)
+ p5 = plot_temperature(sys)
+ p6 = plot_speed_distribution(sys, 20)
+
+ # make gif
+ if gif == 1
+ animate(sys, 1)
+ end
+
+ plot(
+ p1, p2, p3, p4, p5, p6,
+ layout = (2, 3),
+ size = (1280, 720),
+ )
+end
+
+demo_0()