Still trying to build intuition for optimizing Julia code. Here is an MD code I translated from python. It already runs a lot faster than my python version but I feel like it could be faster. I’m more interested in learning optimization techniques than this specific piece of code but I thought this would be a good piece to practice on. When I time the function that does the heavy lifting I’m seeing over 10k allocations. (I’ve set the loop to run just a few iterations for now.) Any ideas for using better style/ optimizing this would be much appreciated. Thanks in advance:
struct MD
nParticles::Int64
boxSize::Float64
positions:: Array{Float64,2}
velocities:: Array{Float64,2}
end
using Random
using LinearAlgebra
#using Pkg
#Pkg.add("StaticArrays")
using StaticArrays
function initializeParticles(nParticles::Int64,boxSize::Float64,lVecs::Array{Float64,2},random::Bool = false):: MD
positions = zeros(nParticles,2)
velocities = zeros(nParticles,2)
deltaR = 0.5
v0=1.
idx = 0
for i =-boxSize-10:boxSize+10
for j =-boxSize-10:boxSize+10
println(i,j)
println(idx)
vec = i * lVecs[1,:] + j * lVecs[2,:] + [0.6, 0.6]
if random
rng = MersenneTwister(1234)
rVec = rand(rng,2)
vec += deltaR * rVec/norm(rVec)
end
if 0 <= vec[1] <= boxSize && 0 <= vec[2] <= boxSize && idx < nParticles
println("adding")
println(i,j)
println(vec)
println(idx)
idx += 1
positions[idx,:] = vec
rng = MersenneTwister(1234)
vVec = rand(rng,2)
velocities[idx,:] = v0 * vVec/norm(vVec)
end
end
end
if idx < nParticles
println("Didn't find all of the requested particles")
println("Requested: ", nParticles)
println("Found: ", idx)
end
MD(nParticles,boxSize,positions,velocities)
end
function forceOnSingleParticle(positions::Array{Float64,2},particle::Array{Float64,1},boxSize::Float64):: Array{Float64,1}
fVec = zeros(2)
modifiedPos = zeros(2)
diffVec = zeros(Float64,2)
for i=1:size(positions,1)
diffVec .= particle - positions[i,:]
if abs(diffVec[1]) > boxSize/2 && abs(diffVec[2]) > boxSize/2
modifiedPos .= positions[i,:] + boxSize * [sign(diffVec[1]) , sign(diffVec[2])]
elseif abs(diffVec[1]) > boxSize/2
modifiedPos .= positions[i,:] + boxSize * [sign(diffVec[1]) , 0]
elseif abs(diffVec[2]) > boxSize/2
modifiedPos .= positions[i,:] + boxSize * [0 , sign(diffVec[2])]
else
modifiedPos .= deepcopy(positions[i,:])
end
diffVec .= particle - modifiedPos
distance = norm(diffVec)
if distance > 0.5
fVec .+= 24 * (2/distance^13 - 1/distance^7) * 1/distance * [diffVec[1], diffVec[2]]
end
end
return fVec
end
function simulate(myMD::MD,dt::Float64,tMax::Float64)
forces = zeros(size(myMD.positions,1),2)
T = 0.4
positions = copy(myMD.positions)
positionsP = copy(myMD.positions)
positionsPP = positions - myMD.velocities * dt
velocities = zeros(Float64,size(positions,1),size(positions,2))
while T > 0.2
for time=0:dt:tMax
#println(time)
#if any(positions > myMD.boxSize)
# exit("lost particles")
#end
for n=1:size(positions,1)
forces[n,:] .= forceOnSingleParticle(positions,positions[n,:],myMD.boxSize)
end
positions .= 2 .* positionsP .- positionsPP .+ forces .* dt^2
velocities .= (positions .- positionsPP)/(2 .* dt)
positionsPP .= copy(positionsP)
positionsP .= copy(positions)
for n=1:size(positions,1)
if positions[n,1] > myMD.boxSize
positions[n,1] .-= myMD.boxSize
end
if positions[n,1] < 0
positions[n,1] .+= myMD.boxSize
end
if positions[n,2] > myMD.boxSize
positions[n,2] .-= myMD.boxSize
end
if positions[n,2] < 0
positions[n,2] .+= myMD.boxSize
end
end
end
T -=0.3
end
positions
end
using Plots
plotly()
dt = .0001
tMax = .0003
lvecs = 1.07 * [[1. 0.]; [0.5 sqrt(3)/2]]
myMD = initializeParticles(16,4.,lvecs)
@time mypositions = simulate(myMD,dt,tMax)
plot(mypositions[:,1],mypositions[:,2],seriestype = :scatter,aspect_ratio=:equal,xlim = (0,4),ylim = (0,4))
positions = [[4 4]; [3.5 1.5]; [0.5 2]]
@time f = forceOnSingleParticle(positions,positions[3,:],5.)
println(f)