1
0
Fork 0
mirror of https://gitlab.rlp.net/mobitar/ReCo.jl.git synced 2024-09-19 19:01:17 +00:00

Renaming and verlet list shrink

This commit is contained in:
MoBit 2021-12-10 03:16:18 +01:00
parent 5001c315ce
commit 50feaee469
11 changed files with 138 additions and 113 deletions

View file

@ -22,7 +22,6 @@ ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
ReinforcementLearning = "158674fc-8238-5cab-b5ba-03dfc80d1318"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

View file

@ -13,46 +13,54 @@ mutable struct Particle
end
end
function restrict_coordinate(value::Float64, l::Float64)
if value < -l
value += 2 * l
elseif value >= l
value -= 2 * l
function restrict_coordinate(value::Float64, half_box_len::Float64)
if value < -half_box_len
value += 2 * half_box_len
elseif value >= half_box_len
value -= 2 * half_box_len
end
return value
end
function restrict_coordinates!(v::SVector{2,Float64}, l::Float64)
return SVector(restrict_coordinate(v[1], l), restrict_coordinate(v[2], l))
function restrict_coordinates!(v::SVector{2,Float64}, half_box_len::Float64)
return SVector(
restrict_coordinate(v[1], half_box_len), restrict_coordinate(v[2], half_box_len)
)
end
function restrict_coordinates!(p::Particle, l::Float64)
p.tmp_c = restrict_coordinates!(p.tmp_c, l)
function restrict_coordinates!(p::Particle, half_box_len::Float64)
p.tmp_c = restrict_coordinates!(p.tmp_c, half_box_len)
return nothing
end
function minimum_image_coordinate(value::Float64, l::Float64)
if value <= -l
value += 2 * l
elseif value > l
value -= 2 * l
function minimum_image_coordinate(value::Float64, half_box_len::Float64)
if value <= -half_box_len
value += 2 * half_box_len
elseif value > half_box_len
value -= 2 * half_box_len
end
return value
end
function minimum_image(v::SVector{2,Float64}, l::Float64)
return SVector(minimum_image_coordinate(v[1], l), minimum_image_coordinate(v[2], l))
function minimum_image(v::SVector{2,Float64}, half_box_len::Float64)
return SVector(
minimum_image_coordinate(v[1], half_box_len),
minimum_image_coordinate(v[2], half_box_len),
)
end
function are_overlapping(
c1::SVector{2,Float64}, c2::SVector{2,Float64}, overlapping_r²::Float64, l::Float64
c1::SVector{2,Float64},
c2::SVector{2,Float64},
overlapping_r²::Float64,
half_box_len::Float64,
)
r⃗₁₂ = c2 - c1 # 1 -> 2
r⃗₁₂ = minimum_image(r⃗₁₂, l)
r⃗₁₂ = minimum_image(r⃗₁₂, half_box_len)
distance² = r⃗₁₂[1]^2 + r⃗₁₂[2]^2

View file

@ -4,7 +4,7 @@ mutable struct PreVector{T}
last_ind::UInt64
v::Vector{T}
PreVector{T}(N) where {T} = new{T}(UInt64(0), Vector{T}(undef, N))
PreVector{T}(n_particles) where {T} = new{T}(UInt64(0), Vector{T}(undef, n_particles))
end
function push!(pv::PreVector{T}, x::T) where {T}

View file

@ -28,13 +28,13 @@ function pair_correlation(sol, variables)
dr = (max_radius - min_radius) / n_r
radius = range(min_radius, max_radius; length=n_r)
N_g = zeros(variables.N, n_r)
N_g = zeros(variables.n_particles, n_r)
Threads.@threads for r_ind in 1:n_r
r = radius[r_ind]
@simd for i in 1:(variables.N)
for j in 1:(variables.N)
@simd for i in 1:(variables.n_particles)
for j in 1:(variables.n_particles)
if i != j
for k in 1:n_last_frames
frame = variables.n_snapshots - k + 1
@ -43,7 +43,7 @@ function pair_correlation(sol, variables)
r⃗₁₂ = c1 - c2
r⃗₁₂ = minimum_image(r⃗₁₂, variables.l)
r⃗₁₂ = minimum_image(r⃗₁₂, variables.half_box_len)
distance = sqrt(r⃗₁₂[1]^2 + r⃗₁₂[2]^2)
@ -62,13 +62,19 @@ function pair_correlation(sol, variables)
r = radius[r_ind]
tmp_g = 0.0
@turbo for i in 1:(variables.N)
@turbo for i in 1:(variables.n_particles)
tmp_g += N_g[i, r_ind]
end
tmp_g *=
(2 * variables.l)^2 /
((variables.N * n_last_frames) * variables.N * 2 * π * r * dr)
(2 * variables.half_box_len)^2 / (
(variables.n_particles * n_last_frames) *
variables.n_particles *
2 *
π *
r *
dr
)
g[r_ind] = tmp_g
end

View file

@ -19,7 +19,7 @@ function animate_bundle!(args)
π2 = 2 * π
for frame in 1:length(bundle_t)
@simd for i in 1:(args.N)
@simd for i in 1:(args.n_particles)
c = bundle_c[i, frame]
args.circles[][i] = Circle(Point2(c[1], c[2]), args.particle_radius)
@ -48,7 +48,7 @@ function animate_bundle!(args)
println("Recording started!")
else
if args.debug && frame > 1
@simd for i in 1:(args.N)
@simd for i in 1:(args.n_particles)
first_ind = 2 * i - 1
second_ind = 2 * i
frame_min_1 = frame - 1
@ -96,7 +96,12 @@ function animate_after_loading(dir, animation_path, sim_consts, framerate, debug
fig = Figure(; resolution=(1080, 1080))
ax = Axis(
fig[1, 1];
limits=(-sim_consts.l, sim_consts.l, -sim_consts.l, sim_consts.l),
limits=(
-sim_consts.half_box_len,
sim_consts.half_box_len,
-sim_consts.half_box_len,
sim_consts.half_box_len,
),
aspect=AxisAspect(1),
xlabel=L"x",
ylabel=L"y",
@ -106,11 +111,11 @@ function animate_after_loading(dir, animation_path, sim_consts, framerate, debug
Colorbar(fig[1, 2]; limits=(0, 2), colormap=color_scheme, label=L"\frac{\varphi}{\pi}")
N = sim_consts.N
n_particles = sim_consts.n_particles
record(fig, animation_path; framerate=framerate) do io
circles = Observable(Vector{Circle}(undef, N))
colors = Observable(Vector{RGBAf}(undef, N))
circles = Observable(Vector{Circle}(undef, n_particles))
colors = Observable(Vector{RGBAf}(undef, n_particles))
segments_x =
segments_y =
@ -118,14 +123,14 @@ function animate_after_loading(dir, animation_path, sim_consts, framerate, debug
skin_circles = interaction_colors = skin_colors = nothing
if debug
segments_x = Observable(zeros(2 * N))
segments_y = Observable(zeros(2 * N))
segments_x = Observable(zeros(2 * n_particles))
segments_y = Observable(zeros(2 * n_particles))
interaction_circles = Observable(Vector{Circle}(undef, N))
skin_circles = Observable(Vector{Circle}(undef, N))
interaction_circles = Observable(Vector{Circle}(undef, n_particles))
skin_circles = Observable(Vector{Circle}(undef, n_particles))
interaction_colors = Observable(Vector{RGBAf}(undef, N))
skin_colors = Observable(Vector{RGBAf}(undef, N))
interaction_colors = Observable(Vector{RGBAf}(undef, n_particles))
skin_colors = Observable(Vector{RGBAf}(undef, n_particles))
end
particle_radius = sim_consts.particle_diameter / 2
@ -146,9 +151,9 @@ function animate_after_loading(dir, animation_path, sim_consts, framerate, debug
@showprogress 1 for (n_bundle, bundle_path) in enumerate(bundle_paths)
bundle::Bundle = JLD2.load_object(bundle_path)
run_vars_file = "$dir/runs/run_vars_$n_bundle.json"
if debug && isfile(run_vars_file)
skin_r::Float64 = JSON3.read(read(run_vars_file, String)).skin_r
run_params_file = "$dir/runs/run_params_$n_bundle.json"
if debug && isfile(run_params_file)
skin_r::Float64 = JSON3.read(read(run_params_file, String)).skin_r
end
args = (;
@ -167,7 +172,7 @@ function animate_after_loading(dir, animation_path, sim_consts, framerate, debug
skin_colors,
particle_radius,
skin_r,
N,
n_particles,
interaction_r,
color_scheme,
n_bundle,

View file

@ -7,14 +7,14 @@ using ReCo
function run_benchmarks(
dir::String="";
N::Int64=1000,
n_particles::Int64=1000,
v::Float64=20.0,
duration::Float64=2.0,
n_bundle_snapshots::Int64=0,
comment="",
)
if length(dir) == 0
dir = init_sim(; N=N, v=v, parent_dir="benchmark")
dir = init_sim(; n_particles=n_particles, v=v, parent_dir="benchmark")
end
benchmark = @benchmark run_sim(
@ -27,7 +27,7 @@ function run_benchmarks(
JSON3.pretty(
f,
Dict(
"N" => N,
"n_particles" => n_particles,
"v" => v,
"duration" => duration,
"n_bundle_snapshots" => n_bundle_snapshots,

View file

@ -7,11 +7,11 @@ struct Bundle
φ::Matrix{Float64}
end
function Bundle(N::Int64, n_snapshots::Int64)
function Bundle(n_particles::Int64, n_snapshots::Int64)
return Bundle(
Vector{Float64}(undef, n_snapshots),
Matrix{SVector{2,Float64}}(undef, (N, n_snapshots)),
Matrix{Float64}(undef, (N, n_snapshots)),
Matrix{SVector{2,Float64}}(undef, (n_particles, n_snapshots)),
Matrix{Float64}(undef, (n_particles, n_snapshots)),
)
end
@ -33,8 +33,8 @@ function save_snapshot!(
return nothing
end
function set_status(dir::String, n_bundles::Int64, T::Float64)
open("$dir/status.json", "w") do f
function set_sim_state(dir::String, n_bundles::Int64, T::Float64)
open("$dir/sim_state.json", "w") do f
JSON3.write(f, Dict("n_bundles" => n_bundles, "T" => round(T; digits=3)))
end
@ -47,7 +47,7 @@ function save_bundle(dir::String, bundle::Bundle, n::Int64, T::Float64)
JLD2.save_object("$bundles_dir/bundle_$n.jld2", bundle)
set_status(dir, n, T)
set_sim_state(dir, n, T)
return nothing
end

View file

@ -35,13 +35,13 @@ function run_sim(
n_bundle_snapshots = min(n_snapshots, n_bundle_snapshots)
status = JSON3.read(read("$dir/status.json", String))
n_bundles = status.n_bundles
sim_state = JSON3.read(read("$dir/sim_state.json", String))
n_bundles = sim_state.n_bundles
bundles_dir = "$dir/bundles"
bundle = JLD2.load_object("$bundles_dir/bundle_$n_bundles.jld2")
particles = generate_particles(bundle, sim_consts.N)
particles = generate_particles(bundle, sim_consts.n_particles)
args = (
v=sim_consts.v,
@ -56,23 +56,26 @@ function run_sim(
μ=sim_consts.μ,
interaction_r=sim_consts.interaction_r,
interaction_r²=sim_consts.interaction_r^2,
N=sim_consts.N,
l=sim_consts.l,
n_particles=sim_consts.n_particles,
half_box_len=sim_consts.half_box_len,
particle_diameter=sim_consts.particle_diameter,
particles=particles,
particles_c=[particles[i].c for i in 1:(sim_consts.N)],
verlet_list=[PreVector{Int64}(sim_consts.N - 1) for i in 1:(sim_consts.N - 1)],
particles_c=[particles[i].c for i in 1:(sim_consts.n_particles)],
verlet_lists=[
PreVector{Int64}(sim_consts.n_particles - i) for
i in 1:(sim_consts.n_particles - 1)
],
n_bundle_snapshots=n_bundle_snapshots,
bundle=Bundle(sim_consts.N, n_bundle_snapshots),
box=Box(SVector(2 * sim_consts.l, 2 * sim_consts.l), skin_r),
bundle=Bundle(sim_consts.n_particles, n_bundle_snapshots),
box=Box(SVector(2 * sim_consts.half_box_len, 2 * sim_consts.half_box_len), skin_r),
)
T0::Float64 = status.T
T0::Float64 = sim_state.T
T = T0 + duration
start_datetime = now()
run_vars = (;
run_params = (;
# Input
duration,
snapshot_at,
@ -98,8 +101,8 @@ function run_sim(
if n_bundle_snapshots > 0
save_data = true
open("$runs_dir/run_vars_$next_bundle.json", "w") do f
JSON3.write(f, run_vars)
open("$runs_dir/run_params_$next_bundle.json", "w") do f
JSON3.write(f, run_params)
end
else
save_data = false

View file

@ -2,12 +2,14 @@ using Distributions: Uniform
using Dates: now
using JSON3: JSON3
function initial_particle_grid_pos(i::Int64, j::Int64, grid_box_width::Float64, l::Float64)
term = -0.5 * grid_box_width - l
function initial_particle_grid_pos(
i::Int64, j::Int64, grid_box_width::Float64, half_box_len::Float64
)
term = -0.5 * grid_box_width - half_box_len
return SVector(i * grid_box_width + term, j * grid_box_width + term)
end
function generate_particles(grid_n::Int64, grid_box_width::Float64, l::Float64)
function generate_particles(grid_n::Int64, grid_box_width::Float64, half_box_len::Float64)
particles = Vector{Particle}(undef, grid_n^2)
id = 1
@ -15,7 +17,9 @@ function generate_particles(grid_n::Int64, grid_box_width::Float64, l::Float64)
for i in 1:grid_n
for j in 1:grid_n
particles[id] = Particle(
id, initial_particle_grid_pos(i, j, grid_box_width, l), rand(Uniform(-π, π))
id,
initial_particle_grid_pos(i, j, grid_box_width, half_box_len),
rand(Uniform(-π, π)),
)
id += 1
@ -25,10 +29,10 @@ function generate_particles(grid_n::Int64, grid_box_width::Float64, l::Float64)
return particles
end
function generate_particles(bundle::Bundle, N::Int64)
particles = Vector{Particle}(undef, N)
function generate_particles(bundle::Bundle, n_particles::Int64)
particles = Vector{Particle}(undef, n_particles)
@simd for id in 1:N
@simd for id in 1:n_particles
particles[id] = Particle(id, bundle.c[id, end], bundle.φ[id, end])
end
@ -36,14 +40,14 @@ function generate_particles(bundle::Bundle, N::Int64)
end
function init_sim(;
N::Int64,
n_particles::Int64,
v::Float64,
δt::Float64=1e-5,
packing_ratio::Float64=0.5,
comment::String="",
parent_dir::String="",
)
@assert N > 0
@assert n_particles > 0
@assert v >= 0
@assert δt in 1e-7:1e-7:1e-4
@assert packing_ratio > 0
@ -56,16 +60,16 @@ function init_sim(;
ϵ = 100.0
interaction_r = 2^(1 / 6) * σ
grid_n = round(Int64, ceil(sqrt(N)))
grid_n = round(Int64, ceil(sqrt(n_particles)))
N = grid_n^2
n_particles = grid_n^2
l = sqrt(N * π / packing_ratio) * σ / 4
grid_box_width = 2 * l / grid_n
half_box_len = sqrt(n_particles * π / packing_ratio) * σ / 4
grid_box_width = 2 * half_box_len / grid_n
sim_consts = (;
# Input
N,
n_particles,
v,
δt,
packing_ratio,
@ -78,12 +82,12 @@ function init_sim(;
ϵ,
interaction_r,
grid_n,
l,
half_box_len,
grid_box_width,
)
particles = generate_particles(grid_n, grid_box_width, l)
bundle = Bundle(N, 1)
particles = generate_particles(grid_n, grid_box_width, half_box_len)
bundle = Bundle(n_particles, 1)
save_snapshot!(bundle, 1, 0.0, particles)
particles = nothing
@ -92,7 +96,7 @@ function init_sim(;
if length(parent_dir) > 0
dir *= "/$parent_dir"
end
dir *= "/$(now())_N=$(N)_v=$(v)_#$(rand(1000:9999))"
dir *= "/$(now())_N=$(n_particles)_v=$(v)_#$(rand(1000:9999))"
if length(comment) > 0
dir *= "_$comment"
end

View file

@ -1,30 +1,30 @@
using StaticArrays: SVector, SMatrix
using LinearAlgebra: eigvals, Hermitian
function project_to_unit_circle(x::Float64, l::Float64)
φ = (x + l) * π / l
function project_to_unit_circle(x::Float64, half_box_len::Float64)
φ = (x + half_box_len) * π / half_box_len
si, co = sincos(φ)
return SVector(co, si)
end
function project_back_from_unit_circle(θ::T, l::Float64) where {T<:Real}
x = θ * l / π - l
return restrict_coordinate(x, l)
function project_back_from_unit_circle(θ::T, half_box_len::Float64) where {T<:Real}
x = θ * half_box_len / π - half_box_len
return restrict_coordinate(x, half_box_len)
end
function center_of_mass(particles::Vector{Particle}, l::Float64)
function center_of_mass(particles::Vector{Particle}, half_box_len::Float64)
x_proj_sum = SVector(0.0, 0.0)
y_proj_sum = SVector(0.0, 0.0)
for p in particles
x_proj_sum += project_to_unit_circle(p.c[1], l)
y_proj_sum += project_to_unit_circle(p.c[2], l)
x_proj_sum += project_to_unit_circle(p.c[1], half_box_len)
y_proj_sum += project_to_unit_circle(p.c[2], half_box_len)
end
# Prevent for example atan(1e-16, 1e-15) != 0 with rounding
digits = 5
# No need for 1/N with atan
# No need for 1/n_particles with atan
# If proj is (0, 0) then COM is 0 or L or -L. Here, 0 is choosen with θ = π
if round(x_proj_sum[1]; digits=digits) == round(x_proj_sum[2]; digits=digits) == 0
x_θ = π
@ -38,21 +38,21 @@ function center_of_mass(particles::Vector{Particle}, l::Float64)
y_θ = atan(y_proj_sum[2], y_proj_sum[1])
end
COM_x = project_back_from_unit_circle(x_θ, l)
COM_y = project_back_from_unit_circle(y_θ, l)
COM_x = project_back_from_unit_circle(x_θ, half_box_len)
COM_y = project_back_from_unit_circle(y_θ, half_box_len)
return SVector(COM_x, COM_y)
end
function gyration_tensor(particles::Vector{Particle}, l::Float64)
COM = center_of_mass(particles, l)
function gyration_tensor(particles::Vector{Particle}, half_box_len::Float64)
COM = center_of_mass(particles, half_box_len)
S11 = 0.0
S12 = 0.0
S22 = 0.0
for p in particles
shifted_c = restrict_coordinates!(p.c - COM, l)
shifted_c = restrict_coordinates!(p.c - COM, half_box_len)
S11 += shifted_c[1]^2
S12 += shifted_c[1] * shifted_c[2]
@ -62,7 +62,7 @@ function gyration_tensor(particles::Vector{Particle}, l::Float64)
return Hermitian(SMatrix{2,2}(S11, S12, S12, S22))
end
function gyration_tensor_eigvals_ratio(particles::Vector{Particle}, l::Float64)
ev = eigvals(gyration_tensor(particles, l)) # Eigenvalues are sorted
function gyration_tensor_eigvals_ratio(particles::Vector{Particle}, half_box_len::Float64)
ev = eigvals(gyration_tensor(particles, half_box_len)) # Eigenvalues are sorted
return ev[1] / ev[2]
end

View file

@ -8,29 +8,29 @@ import Base: wait
rand_normal01() = rand(Normal(0, 1))
function push_to_verlet_list(verlet_list, i, j)
function push_to_verlet_list!(verlet_lists, i, j)
if i < j
push!(verlet_list[i], Int64(j))
push!(verlet_lists[i], Int64(j))
else
push!(verlet_list[j], Int64(i))
push!(verlet_lists[j], Int64(i))
end
return nothing
end
function update_verlet_list!(args, cl)
@simd for pv in args.verlet_list
reset!(pv)
function update_verlet_lists!(args, cl)
@simd for pre_vec in args.verlet_lists
reset!(pre_vec)
end
@simd for i in 1:(args.N)
@simd for i in 1:(args.n_particles)
args.particles_c[i] = args.particles[i].c
end
cl = UpdateCellList!(args.particles_c, args.box, cl; parallel=false)
map_pairwise!(
(x, y, i, j, d2, output) -> push_to_verlet_list(args.verlet_list, i, j),
(x, y, i, j, d2, output) -> push_to_verlet_list!(args.verlet_lists, i, j),
nothing,
args.box,
cl;
@ -41,16 +41,16 @@ function update_verlet_list!(args, cl)
end
function euler!(args)
for id1 in 1:(args.N - 1)
for id1 in 1:(args.n_particles - 1)
p1 = args.particles[id1]
p1_c = p1.c
verlet_list = args.verlet_list[id1]
verlet_list = args.verlet_lists[id1]
for id2 in view(verlet_list.v, 1:(verlet_list.last_ind))
p2 = args.particles[id2]
overlapping, r⃗₁₂, distance² = are_overlapping(
p1_c, p2.c, args.interaction_r², args.l
p1_c, p2.c, args.interaction_r², args.half_box_len
)
if overlapping
@ -72,7 +72,7 @@ function euler!(args)
p.φ += args.c₄ * rand_normal01()
restrict_coordinates!(p, args.l)
restrict_coordinates!(p, args.half_box_len)
p.c = p.tmp_c
end
@ -98,7 +98,7 @@ function simulate(
task::Union{Task,Nothing} = nothing
cl = CellList(args.particles_c, args.box; parallel=false)
cl = update_verlet_list!(args, cl)
cl = update_verlet_lists!(args, cl)
start_time = now()
println("Started simulation at $start_time.")
@ -121,7 +121,7 @@ function simulate(
end
if integration_step % n_steps_before_verlet_list_update == 0
cl = update_verlet_list!(args, cl)
cl = update_verlet_lists!(args, cl)
end
euler!(args)