From a001c0310454bddf11cb96d28593e10d7109f2e7 Mon Sep 17 00:00:00 2001 From: dpachner02 Date: Thu, 12 Jun 2025 11:09:30 +0200 Subject: [PATCH] Add Jaguar button | parameter updates working but not reflected in GLMakie yet --- scripts/main.jl | 2 +- src/visualization.jl | 113 +++++++++++++++++++++++++++++++------------ 2 files changed, 82 insertions(+), 33 deletions(-) diff --git a/scripts/main.jl b/scripts/main.jl index e5566c6..cf2b776 100644 --- a/scripts/main.jl +++ b/scripts/main.jl @@ -17,9 +17,9 @@ F, k = Observable(0.060), Observable(0.062) params_obs = Observable(GSParams(N, dx, Du[], Dv[], F[], k[])) lift(Du, Dv, F, k) do u, v, f, ki params_obs[] = GSParams(N, dx, u, v, f, ki) + println("lifted") end - U = ones(N, N) V = zeros(N, N) heat_obs = Observable(U) diff --git a/src/visualization.jl b/src/visualization.jl index ec4e778..d36205e 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -1,18 +1,20 @@ module Visualization include("gray_scott_solver.jl") using GLMakie, Observables, Makie +using Random using .GrayScottSolver + """ step_through_solution(sol::SolutionType, N::Int) Function for visualization for the output of run_simulation # Arguments - - `sol`: computed differential equation by run_simulation - - `N`: size of the N×N grid + - sol: computed differential equation by run_simulation + - N: size of the N×N grid # Returns - - ``: Displays created figure + - Displays created figure """ function step_through_solution(sol, N::Int) fig = Figure(resolution=(600, 600)) @@ -24,37 +26,67 @@ function step_through_solution(sol, N::Int) # Initialize heatmap with first time step u0 = reshape(sol[1][1:N^2], N, N) heat_obs = Observable(u0) - hmap = heatmap!(ax, heat_obs, colormap=:magma) + heatmap!(ax, heat_obs, colormap=:magma) on(textbox.stored_string) do s F[] = parse(Float64, s) end + # Update heatmap on slider movement on(slider.value) do i u = reshape(sol[i][1:N^2], N, N) heat_obs[] = u end - display(fig) end + function coord_to_index(x, y, N) ix = clamp(round(Int, x), 1, N) iy = clamp(round(Int, y), 1, N) return ix, iy end + function reset!(U, V, heat_obs) U .= 1.0 V .= 0.0 + # Default starting point for Run + default_start!(U, V) + heat_obs[] = copy(U) +end + +function default_start!(U, V) 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 starting_points!(U, V) + N = size(U, 1) + radius = 10 + jitter = 5 + margin = radius + 2 + rels = [ + (1/4, 1/4), (3/4, 1/4), (1/2, 1/2), + (1/4, 3/4), (3/4, 3/4), (1/2, 1/8) + ] + for (px, py) in rels + cx = clamp(round(Int, px * N) + rand(-jitter:jitter), margin, N - margin) + cy = clamp(round(Int, py * N) + rand(-jitter:jitter), margin, N - margin) + for x in (cx - radius):(cx + radius), y in (cy - radius):(cy + radius) + if 1 ≤ x ≤ N && 1 ≤ y ≤ N && hypot(x - cx, y - cy) ≤ radius + U[x, y] = 0.50 + V[x, y] = 0.25 + end + end + end +end + function param_box!(grid, row, labeltxt, observable::Observable) Label(grid[row, 1], labeltxt) - box = Textbox(grid[row, 2], validator=Float64, width=50, placeholder=labeltxt, stored_string="$(observable[])") + box = Textbox(grid[row, 2], validator=Float64, width=50, + placeholder=labeltxt, stored_string="$(observable[])") on(box.stored_string) do s try observable[] = parse(Float64, s) @@ -70,69 +102,86 @@ function build_ui(U, V, Du, Dv, F, k, params_obs, heat_obs) fig = Figure(size=(800, 800)) gh = GridLayout(fig[1, 1]) ax = Axis(gh[1, 1]) - hm = Makie.heatmap!(ax, heat_obs, colormap=:viridis) + heatmap!(ax, heat_obs, colormap=:viridis) deactivate_interaction!(ax, :rectanglezoom) ax.aspect = DataAspect() - run_label = Observable{String}("Run") + run_label = Observable("Run") stepsize = Observable(30) - # # Controls + + # Controls fig[2, 1] = buttongrid = GridLayout(ax.scene, tellwidth=false) - btn_step = Button(buttongrid[1, 1], width=50, label="Step") - btn_start = Button(buttongrid[1, 2], width=50, label=run_label) - btn_reset = Button(buttongrid[1, 3], width=50, label="Reset") - slidergrid = SliderGrid(fig[3, 1], (label="Speed", range=1:1:100, format="{}x", width=350, startvalue=stepsize[])) + btn_step = Button(buttongrid[1, 1], width=60, label="Step") + btn_start = Button(buttongrid[1, 2], width=60, label=run_label) + btn_reset = Button(buttongrid[1, 3], width=60, label="Reset") + btn_Jaguar = Button(buttongrid[1, 4], width=60, label="Jaguar") + slidergrid = SliderGrid(fig[3, 1], (label="Speed", range=1:100, + format="{}x", width=350, + startvalue=stepsize[])) speed_slider = slidergrid.sliders[1].value - gh[1, 2] = textboxgrid = GridLayout(ax.scene, tellwidth=false) rowsize!(gh, 1, Relative(1.0)) - - param_box!(textboxgrid, 1, "Du", Du) param_box!(textboxgrid, 2, "Dv", Dv) param_box!(textboxgrid, 3, "Feed", F) param_box!(textboxgrid, 4, "kill", k) - # Timer and state for animation - running = Observable(false) + println("aufruf") + running = Observable(false) on(running) do r run_label[] = r ? "Pause" : "Run" end + on(speed_slider) do s - try - stepsize[] = s - println("Changed stepsize to $s") - catch - @warn "Invalid input for $s" - end + stepsize[] = s + println("Changed stepsize to $s") end - # Button Listeners + on(btn_step.clicks) do _ multi_step!((U, V), stepsize[], heat_obs, params_obs) end on(btn_start.clicks) do _ running[] = !running[] + if running[] + reset!(U, V, heat_obs) + @async while running[] + multi_step!((U, V), stepsize[], heat_obs, params_obs) + sleep(0.0015) + end + end end - on(btn_start.clicks) do _ - @async while running[] - multi_step!((U, V), stepsize[], heat_obs, params_obs) - sleep(0.0015) # ~20 FPS + on(btn_Jaguar.clicks) do _ + + Du[] = 0.142 + Dv[] = 0.078 + F[] = 0.0617 + k[] = 0.062 + + if !running[] + running[] = true + U .= 1.0; V .= 0.0 + @async while running[] + multi_step!((U, V), stepsize[], heat_obs, params_obs) + sleep(0.0015) + end end + + starting_points!(U, V) + heat_obs[] = copy(U) end on(btn_reset.clicks) do _ running[] = false reset!(U, V, heat_obs) - end + return fig end - export step_through_solution, build_ui end