diff options
author | sotech117 <michael_foiani@brown.edu> | 2024-05-02 19:33:11 -0400 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2024-05-02 19:33:11 -0400 |
commit | 95eb65429d24a897307601415c716e9042033982 (patch) | |
tree | c6a7cf8141eaae09fd16d64f9ffacae16bbab29a /t/old/t.jl | |
parent | c048f9f2219897ff3cc20a50d459911db3496a0a (diff) |
update naming
Diffstat (limited to 't/old/t.jl')
-rw-r--r-- | t/old/t.jl | 755 |
1 files changed, 0 insertions, 755 deletions
diff --git a/t/old/t.jl b/t/old/t.jl deleted file mode 100644 index 6a06777..0000000 --- a/t/old/t.jl +++ /dev/null @@ -1,755 +0,0 @@ -# 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() |