SCJ_Projekt/scripts/run_simulation.jl

148 lines
3.5 KiB
Julia

using GLMakie, Observables
using .AnimalFurFHN
# Parameters and initial conditions
N = 128
dx = 1.0
Du, Dv = Observable(0.16), Observable(0.08)
F, k = Observable(0.060), Observable(0.062)
dt = 1.0
params_obs = Observable(AnimalFurFHN.GSParams(N, dx, 0.16, 0.08, 0.08, 0.06))
function update_params!(params_obs, u, v, feed, kill)
old = params_obs[]
params_obs[] = AnimalFurFHN.GSParams(old.N, old.dx, u, v, feed, kill)
end
lift(Du, Dv, F, k) do u, v, F, k
update_params!(params_obs, u, v, F, k)
end
U = ones(N, N)
V = zeros(N, N)
center = N ÷ 2
radius = 10
U[center-radius:center+radius, center-radius:center+radius] .= 0.50
V[center-radius:center+radius, center-radius:center+radius] .= 0.25
# Observable holding current U for heatmap
heat_obs = Observable(U)
function laplacian5(f)
h2 = dx^2
left = f[2:end-1, 1:end-2]
right = f[2:end-1, 3:end]
down = f[3:end, 2:end-1]
up = f[1:end-2, 2:end-1]
center = f[2:end-1, 2:end-1]
return (left .+ right .+ down .+ up .- 4 .* center) ./ h2
end
function step!(U, V)
lap_u = laplacian5(U)
lap_v = laplacian5(V)
u = U[2:end-1, 2:end-1]
v = V[2:end-1, 2:end-1]
uvv = u .* v .* v
u_new = u .+ (Du[] .* lap_u .- uvv .+ F[] .* (1 .- u)) .* dt
v_new = v .+ (Dv[] .* lap_v .+ uvv .- (F[] .+ k[]) .* v) .* dt
# Update with new values
U[2:end-1, 2:end-1] .= u_new
V[2:end-1, 2:end-1] .= v_new
# Periodic boundary conditions
U[1, :] .= U[end-1, :]
U[end, :] .= U[2, :]
U[:, 1] .= U[:, end-1]
U[:, end] .= U[:, 2]
V[1, :] .= V[end-1, :]
V[end, :] .= V[2, :]
V[:, 1] .= V[:, end-1]
V[:, end] .= V[:, 2]
# Update heatmap observable
heat_obs[] = copy(U)
end
function multi_step!(state, n_steps)
for _ in 1:n_steps
step!(state[1], state[2])
end
end
# Build GUI
fig = Figure(size=(600, 600))
ax = Axis(fig[1, 1])
hm = Makie.heatmap!(ax, heat_obs, colormap=:magma)
ax.aspect = DataAspect()
# # Controls
fig[2, 1] = buttongrid = GridLayout(tellwidth=false)
btn_step = Button(buttongrid[1, 1], label="Step")
btn_start = Button(buttongrid[1, 2], label="Start")
btn_stop = Button(buttongrid[1, 3], label="Stop")
btn_reset = Button(buttongrid[1, 4], label="Reset")
fig[3, 1] = textboxgrid = GridLayout(tellwidth=false)
box_u = Textbox(textboxgrid[1, 1], validator=Float64, placeholder="word")
# box_v = Textbox(textboxgrid[1, 2], validator=Float64, placeholder="word")
# box_feed = Textbox(textboxgrid[1, 3], validator=Float64, placeholder="word")
# box_kill = Textbox(textboxgrid[1, 4], validator=Float64, placeholder="word")
# Timer and state for animation
running = Observable(false)
function reset!(U, V, heat_obs)
U .= 1.0
V .= 0.0
center = size(U, 1) ÷ 2
radius = 10
U[center-radius:center+radius, center-radius:center+radius] .= 0.50
V[center-radius:center+radius, center-radius:center+radius] .= 0.25
heat_obs[] = copy(U)
end
function animation_loop()
while running[]
# step!(U, V)
multi_step!((U, V), 30)
sleep(0.05) # ~20 FPS
end
end
on(box_u.stored_string) do s
try
Du[] = parse(Float64, s)
println("Change Du ", Du[])
catch
@warn "Invalid input for Du: $s"
end
end
on(btn_step.clicks) do _
multi_step!((U, V), 30)
end
on(btn_start.clicks) do _
if !running[]
running[] = true
@async animation_loop()
end
end
on(btn_stop.clicks) do _
running[] = false
end
on(btn_reset.clicks) do _
running[] = false
reset!(U, V, heat_obs)
end
display(fig)