rand_normal01() = rand(Normal(0, 1)) function update_verlet_list!(args) @simd for pv in args.verlet_list reset!(pv) end for i in 1:(args.N - 1) for j in (i + 1):(args.N) p1 = args.particles[i] p2 = args.particles[j] overlapping = are_overlapping(p1, p2, args.skin_r², args.l).overlapping if overlapping push!(args.verlet_list[i], j) end end end return nothing end function euler!(args) for i in 1:(args.N - 1) p = args.particles[i] verlet_list = args.verlet_list[p.id] for j in 1:(verlet_list.last_ind) p2 = args.particles[verlet_list.v[j]] overlapping, r⃗₁₂, distance² = are_overlapping( p, p2, args.interaction_r², args.l ) if overlapping c = args.c₁ / (distance²^4) * (args.c₂ / (distance²^3) - 1) @turbo for k in 1:2 dck = c * r⃗₁₂[k] p.tmp_c[k] -= dck p2.tmp_c[k] += dck end end end end @simd for p in args.particles e = SVector(cos(p.φ), sin(p.φ)) @turbo for i in 1:2 p.tmp_c[i] += args.vδt * e[i] + args.c₃ * rand_normal01() end p.φ += args.c₄ * rand_normal01() restrict_coordinates!(p; l=args.l) update!(p) end return nothing end function simulate( args, δt::Float64, T::Float64, n_steps_before_verlet_list_update::Int64, n_steps_before_save::Int64, ) sol = Solution(args.N, args.n_frames) frame = 0 frame = save_frame!(sol, frame, 0.0, args.particles) start_time = now() println("Started simulation at $start_time.") @showprogress 0.6 for (integration_step, t) in enumerate(0:δt:T) if integration_step % n_steps_before_save == 0 frame = save_frame!(sol, frame, t, args.particles) end if integration_step % n_steps_before_verlet_list_update == 0 update_verlet_list!(args) end euler!(args) end end_time = now() elapsed_time = canonicalize(CompoundPeriod(end_time - start_time)) println("Simulation done at $end_time and took $elapsed_time.") return (; sol, end_time) end