rand_normal01() = rand(Normal(0, 1)) function push_to_verlet_list!(verlet_lists, i, j) if i < j push!(verlet_lists[i], Int64(j)) else push!(verlet_lists[j], Int64(i)) end return nothing end 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_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_lists, i, j), nothing, args.box, cl; parallel=false, ) return cl end function euler!( args, first_integration_step::Bool, env_helper::Union{RL.EnvHelper,Nothing}, state_update_helper_hook::Function, state_update_hook::Function, update_table_and_actions_hook::Function, ) for id1 in 1:(args.n_particles - 1) p1 = args.particles[id1] p1_c = p1.c 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.half_box_len ) state_update_helper_hook(env_helper, id1, id2, r⃗₁₂) if overlapping factor = args.c₁ / (distance²^4) * (args.c₂ / (distance²^3) - 1.0) dc = factor * r⃗₁₂ p1.tmp_c -= dc p2.tmp_c += dc end end end state_update_hook(env_helper, args.particles) @simd for p in args.particles si, co = sincos(p.φ) p.tmp_c += SVector( args.v₀δt * co + args.c₃ * rand_normal01(), args.v₀δt * si + args.c₃ * rand_normal01(), ) restrict_coordinates!(p, args.half_box_len) update_table_and_actions_hook(env_helper, p, first_integration_step) RL.act_hook(env_helper, p, args.δt, si, co) p.φ += args.c₄ * rand_normal01() p.c = p.tmp_c end return nothing end Base.wait(::Nothing) = nothing gen_run_additional_hooks(::Nothing, args...) = false function gen_run_additional_hooks(env_helper::RL.EnvHelper, integration_step::Int64) return (integration_step % env_helper.shared.n_steps_before_actions_update == 0) || (integration_step == 1) end function simulate( args, T0::Float64, T::Float64, n_steps_before_verlet_list_update::Int64, n_steps_before_snapshot::Int64, n_bundles::Int64, dir::String, save_data::Bool, env_helper::Union{RL.EnvHelper,Nothing}, ) bundle_snapshot_counter = 0 task::Union{Task,Nothing} = nothing cl = CellList(args.particles_c, args.box; parallel=false) cl = update_verlet_lists!(args, cl) first_integration_step = true state_update_helper_hook = state_update_hook = update_table_and_actions_hook = empty_hook start_time = now() println("Started simulation at $start_time.") @showprogress 0.6 for (integration_step, t) in enumerate(T0:(args.δt):T) if (integration_step % n_steps_before_snapshot == 0) && save_data wait(task) bundle_snapshot_counter += 1 save_snapshot!(args.bundle, bundle_snapshot_counter, t, args.particles) if bundle_snapshot_counter == args.n_bundle_snapshots task = @async begin bundle_snapshot_counter = 0 n_bundles += 1 save_bundle(dir, args.bundle, n_bundles, t) end end end if integration_step % n_steps_before_verlet_list_update == 0 cl = update_verlet_lists!(args, cl) end run_additional_hooks = gen_run_additional_hooks(env_helper, integration_step) if run_additional_hooks RL.pre_integration_hook(env_helper) state_update_helper_hook = RL.state_update_helper_hook state_update_hook = RL.state_update_hook update_table_and_actions_hook = RL.update_table_and_actions_hook end euler!( args, first_integration_step, env_helper, state_update_helper_hook, state_update_hook, update_table_and_actions_hook, ) if run_additional_hooks state_update_helper_hook = state_update_hook = update_table_and_actions_hook = empty_hook end first_integration_step = false end wait(task) if bundle_snapshot_counter > 0 bundle = first_n_snapshots(args.bundle, bundle_snapshot_counter) n_bundles += 1 save_bundle(dir, bundle, n_bundles, T) end end_time = now() elapsed_time = Dates.canonicalize(Dates.CompoundPeriod(end_time - start_time)) println("Simulation done at $end_time and took $elapsed_time.") return nothing end