From 99bf6cfdb684938b01b929f8bb4211b8139f2a03 Mon Sep 17 00:00:00 2001 From: GeorgeR227 <78235421+GeorgeR227@users.noreply.github.com> Date: Thu, 20 Jun 2024 12:38:10 -0400 Subject: [PATCH] record_dynamics function This function is meant as a helper to quickly generate animations of a physics while still allowing for customizability in the output. --- Project.toml | 3 ++ docs/src/ch/cahn-hilliard.md | 25 ++++++++-------- ext/DecapodesMakieExt.jl | 55 ++++++++++++++++++++++++++++++++++++ src/Decapodes.jl | 7 ++++- src/operators.jl | 4 ++- src/simulation.jl | 12 ++++---- 6 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 ext/DecapodesMakieExt.jl diff --git a/Project.toml b/Project.toml index 91db6e8e..8f7c773d 100644 --- a/Project.toml +++ b/Project.toml @@ -17,9 +17,11 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [weakdeps] CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" [extensions] DecapodesCUDAExt = "CUDA" +DecapodesMakieExt = "Makie" [compat] ACSets = "0.2" @@ -34,6 +36,7 @@ JSON = "0.21" Krylov = "0.9.6" LinearAlgebra = "1.9" MLStyle = "0.4.17" +Makie = "0.21" Markdown = "1.9" OrdinaryDiffEq = "6.47" PreallocationTools = "0.4" diff --git a/docs/src/ch/cahn-hilliard.md b/docs/src/ch/cahn-hilliard.md index 421876a1..0680df69 100644 --- a/docs/src/ch/cahn-hilliard.md +++ b/docs/src/ch/cahn-hilliard.md @@ -75,7 +75,7 @@ constants = (D = 0.5, γ = 0.5); fig = Figure() # hide ax = CairoMakie.Axis(fig[1,1], aspect=1) # hide msh = CairoMakie.mesh!(ax, s, color=C, colormap=:jet, colorrange=extrema(C)) # hide -Colorbar(fig[1,2], msh) +Colorbar(fig[1,2], msh) # hide save("CahnHilliard_initial.png", fig) # hide nothing # hide ``` @@ -102,21 +102,18 @@ soln.retcode And we can see the result as a gif. -```@setup DEC -function create_gif(solution, file_name) - frames = 200 - fig = Figure() - ax = CairoMakie.Axis(fig[1,1]) - msh = CairoMakie.mesh!(ax, s, color=solution(0).C, colormap=:jet, colorrange=extrema(solution(0).C)) - Colorbar(fig[1,2], msh) - CairoMakie.record(fig, file_name, range(0.0, tₑ; length=frames); framerate = 15) do t - msh.color = solution(t).C - end -end -create_gif(soln, "CahnHilliard_Rect.gif") +```@example DEC +dynam = t -> soln(t).C +frames = 200 + +mesh_args = (colormap = :jet, colorrange = extrema(dynam(0))) +record_args = (framerate = 30,) + +record_dynamics(dynam, s, "CahnHilliard_Rect.webm", range(0.0, tₑ; length = frames); + mesh_args = mesh_args, record_args = record_args) ``` -!["CahnHilliardRes"](CahnHilliard_Rect.gif) +!["CahnHilliardRes"](CahnHilliard_Rect.webm) ```@example INFO DocInfo.get_report(info) # hide diff --git a/ext/DecapodesMakieExt.jl b/ext/DecapodesMakieExt.jl new file mode 100644 index 00000000..79357a23 --- /dev/null +++ b/ext/DecapodesMakieExt.jl @@ -0,0 +1,55 @@ +module DecapodesMakieExt + +using CombinatorialSpaces +using Makie +import Decapodes: record_dynamics + +""" + record_dynamics(dynamics, mesh::HasDeltaSet, path::AbstractString, iter; use_colorbar=true, figure_args=NamedTuple(), axis_args=NamedTuple(), mesh_args=NamedTuple(), colorbar_args=NamedTuple(), record_args=NamedTuple()) + +The Decapodes implementation of Makie's `record` function. This function is meant serve as a helper function +to quickly generate animations based on the resulting dynamics of a Decapodes. + +**Arguments:** + +`dynamics`: A function that accepts a time and returns the value of a particular state variable at that time. + +`mesh`: A CombinatorialSpaces mesh upon which the Decapode was run. + +`path`: The path of the created file recording. + +`iter`: The range of times where `dynamics` will be sampled. + +**Keyword arguments:** + +`use_colorbar = true`: Determines whether display a colorbar alongside the recording. + +`figure_args`: Keyword arguments passed into Makie's `Figure` funcion. + +`axis_args`: Keyword arguments passed into Makie's `Axis` funcion. + +`mesh_args`: Keyword argumentsp assed into Makie's `mesh!` function. Note that `color` is already used to take the value of dynamics at time `t`. + +`colorbar_args`: Keyword arguments passed into Makie's `Colorbar` funcion. Note that if `use_colorbar = false` these will have no effect. + +`record_args`: Keyword arguments passed into Makie's `record` funcion. + +""" +function record_dynamics(dynamics, mesh::HasDeltaSet, path::AbstractString, iter; use_colorbar=true, figure_args=NamedTuple(), axis_args=NamedTuple(), mesh_args=NamedTuple(), colorbar_args=NamedTuple(), record_args=NamedTuple()) + + time = Observable(0.0) + lift_dynam = @lift(dynamics($time)) + + figure = Makie.Figure(;figure_args...) + ax = Makie.Axis(figure[1,1]; axis_args...) + + makie_msh = Makie.mesh!(ax, mesh; color=lift_dynam, mesh_args...) + + use_colorbar ? Makie.Colorbar(figure[1,2], makie_msh; colorbar_args...) : nothing + + Makie.record(figure, path, iter; record_args...) do t + time[] = t + end +end + +end diff --git a/src/Decapodes.jl b/src/Decapodes.jl index 4f2d0956..bdb0f3b7 100644 --- a/src/Decapodes.jl +++ b/src/Decapodes.jl @@ -7,7 +7,12 @@ using MLStyle export gensim, evalsim, compile, compile_env, default_dec_matrix_generate, default_dec_cu_matrix_generate, default_dec_generate, -CPUBackend, CUDABackend, CPUTarget, CUDATarget +CPUBackend, CUDABackend, CPUTarget, CUDATarget, +record_dynamics + +function record_dynamics() + error("Please load Makie.jl to use this function") +end; include("operators.jl") include("simulation.jl") diff --git a/src/operators.jl b/src/operators.jl index 80935186..3ebb9af8 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -5,7 +5,9 @@ using Krylov using LinearAlgebra using SparseArrays -function default_dec_cu_matrix_generate() end; +function default_dec_cu_matrix_generate() + error("Please load CUDA.jl to use this function") +end; function default_dec_matrix_generate(sd::HasDeltaSet, my_symbol::Symbol, hodge::DiscreteHodge) op = @match my_symbol begin diff --git a/src/simulation.jl b/src/simulation.jl index dd650010..a7128091 100644 --- a/src/simulation.jl +++ b/src/simulation.jl @@ -375,7 +375,7 @@ Function that compiles the computation body. `d` is the input Decapode, `inputs` `alloc_vec` should be empty when passed in, `optimizable_dec_operators` is a collection of all DEC operator symbols that can use special in-place methods, `dimension` is the dimension of the problem (usually 1 or 2), `stateeltype` is the type of the state elements (usually Float32 or Float64), `code_target` determines what architecture the code is compiled for (either CPU or CUDA), and `preallocate` -which is set to `true` by default and determines if intermediate results can be preallocated.. +which is set to `true` by default and determines if intermediate results can be preallocated. """ function compile(d::SummationDecapode, inputs::Vector{Symbol}, alloc_vectors::Vector{AllocVecCall}, optimizable_dec_operators::Set{Symbol}, dimension::Int, stateeltype::DataType, code_target::AbstractGenerationTarget, preallocate::Bool) # Get the Vars of the inputs (probably state Vars). @@ -679,14 +679,14 @@ Base.showerror(io::IO, e::UnsupportedStateeltypeException) = print(io, "Decapode """ gensim(user_d::SummationDecapode, input_vars::Vector{Symbol}; dimension::Int=2, stateeltype::DataType = Float64, code_target::AbstractGenerationTarget = CPUTarget(), preallocate::Bool = true) -Generates the entire code body for the simulation function. The returned simulation function can then be combined with a mesh, provided by `CombinatorialSpaces`, and a function describing symbol +Generates the entire code body for the simulation function. The returned simulation function can then be combined with a mesh, provided by `CombinatorialSpaces`, and a function describing symbol to operator mappings to return a simulator that can be used to solve the represented equations given initial conditions. - + **Arguments:** - -`user_d`: The user passed Decapode for which simulation code will be generated. (This is not modified) -`input_vars` is the collection of variables whose values are known at the beginning of the simulation. (Defaults to all state variables and literals in the Decapode) +`user_d`: The user passed Decapode for which simulation code will be generated. (This is not modified) + +`input_vars`: is the collection of variables whose values are known at the beginning of the simulation. (Defaults to all state variables and literals in the Decapode) **Keyword arguments:**