Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In-situ visualization #0: Make GLMakie available in 2D TreeMesh VisualizationCallback #2225

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[weakdeps]
Convex = "f65535da-76fb-5f13-bab9-19810c17039a"
ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199"
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"

[extensions]
TrixiConvexECOSExt = ["Convex", "ECOS"]
TrixiGLMakieExt = "GLMakie"
TrixiMakieExt = "Makie"
TrixiNLsolveExt = "NLsolve"

Expand All @@ -77,6 +79,7 @@ ECOS = "1.1.2"
EllipsisNotation = "1.0"
FillArrays = "0.13.2, 1"
ForwardDiff = "0.10.24"
GLMakie = "0.9"
HDF5 = "0.16.10, 0.17"
IfElse = "0.1"
LinearAlgebra = "1"
Expand Down Expand Up @@ -120,5 +123,6 @@ julia = "1.10"
[extras]
Convex = "f65535da-76fb-5f13-bab9-19810c17039a"
ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199"
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
78 changes: 78 additions & 0 deletions examples/tree_2d_dgsem/elixir_advection_amr_visualization_makie.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

using OrdinaryDiffEq
using Trixi
using GLMakie

###############################################################################
# semidiscretization of the linear advection equation

advection_velocity = (0.2, -0.7)
equations = LinearScalarAdvectionEquation2D(advection_velocity)

function initial_condition_gauss_largedomain(x, t,
equation::LinearScalarAdvectionEquation2D)
# Store translated coordinate for easy use of exact solution
domain_length = SVector(10, 10)
x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t, domain_length)

return SVector(exp(-(x_trans[1]^2 + x_trans[2]^2)))
end
initial_condition = initial_condition_gauss_largedomain

solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs)

coordinates_min = (-5.0, -5.0)
coordinates_max = (5.0, 5.0)
mesh = TreeMesh(coordinates_min, coordinates_max,
initial_refinement_level = 3,
n_cells_max = 30_000)

semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)

###############################################################################
# ODE solvers, callbacks etc.

tspan = (0.0, 20.0)
ode = semidiscretize(semi, tspan)

summary_callback = SummaryCallback()

analysis_interval = 100
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
extra_analysis_integrals = (entropy,))

alive_callback = AliveCallback(analysis_interval = analysis_interval)

save_solution = SaveSolutionCallback(interval = 100,
save_initial_solution = true,
save_final_solution = true,
solution_variables = cons2prim)

# Enable in-situ visualization with a new plot generated every 20 time steps
# and additional plotting options passed as keyword arguments
visualization = VisualizationCallback(interval = 100, clims = (0, 1),
plot_creator = Trixi.show_plot_makie)

amr_controller = ControllerThreeLevel(semi, IndicatorMax(semi, variable = first),
base_level = 3,
med_level = 4, med_threshold = 0.1,
max_level = 5, max_threshold = 0.6)
amr_callback = AMRCallback(semi, amr_controller,
interval = 5,
adapt_initial_condition = true,
adapt_initial_condition_only_refine = true)

stepsize_callback = StepsizeCallback(cfl = 1.6)

callbacks = CallbackSet(summary_callback,
analysis_callback, alive_callback,
save_solution, visualization,
amr_callback, stepsize_callback);

###############################################################################
# run the simulation

sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
summary_callback() # print the timer summary
51 changes: 51 additions & 0 deletions ext/TrixiGLMakieExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Package extension for adding Makie-based features to Trixi.jl
module TrixiGLMakieExt

# Required for visualization code
using GLMakie

# Use functions that are to be extended and additional symbols that are not exported
using Trixi: Trixi, @unpack, @muladd

@muladd begin
#! format: noindent

# converts a single int into a tuple of ints, to get a square arrangement
# example: f(1) = (1,1) f(2) = (2,1) f(3) = (2,2) f(4) = (1,2)
function makieLayoutHelper(n)
if n == 1
return (1, 1)
end
t = makieLayoutHelper(n - 1)
if t[1] == 1
return (t[2] + 1, 1)
elseif t[1] > t[2]
return (t[1], t[2] + 1)
elseif t[2] >= t[1]
return (t[1] - 1, t[2])
end
end

function Trixi.show_plot_makie(visualization_callback, plot_data, variable_names;
show_mesh = true, plot_arguments = Dict{Symbol, Any}(),
time = nothing, timestep = nothing)
if visualization_callback.figure === nothing
@info "Creating new GLMakie figure"
visualization_callback.figure = GLMakie.Figure()
for v in 1:size(variable_names)[1]
push!(visualization_callback.axis,
GLMakie.Axis(visualization_callback.figure[makieLayoutHelper(v)...],
title = variable_names[v]))
end
GLMakie.display(visualization_callback.figure)
end

@unpack axis = visualization_callback
for v in 1:size(variable_names)[1]
GLMakie.heatmap!(axis[v], plot_data.x, plot_data.y, plot_data.data[v])
end

# TODO: handle `show_mesh`
end
end # @muladd
end # module TrixiGLMakieExt
44 changes: 28 additions & 16 deletions src/callbacks_step/visualization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
#! format: noindent

mutable struct VisualizationCallback{SolutionVariables, VariableNames, PlotDataCreator,
PlotCreator}
PlotCreator, Figure, Axis}
interval::Int
solution_variables::SolutionVariables
variable_names::VariableNames
show_mesh::Bool
plot_data_creator::PlotDataCreator
plot_creator::PlotCreator
figure::Figure
axis::Axis
plot_arguments::Dict{Symbol, Any}
end

Expand Down Expand Up @@ -99,19 +101,25 @@ function VisualizationCallback(; interval = 0,
solution_variables, variable_names,
show_mesh,
plot_data_creator, plot_creator,
nothing, [],
Dict{Symbol, Any}(plot_arguments))

# Warn users if they create a visualization callback without having loaded the Plots package
# Warn users if they create a visualization callback without having loaded a plotting
# package
#
# Note: This warning is added for convenience, as Plots is the only "officially" supported
# visualization package right now. However, in general nothing prevents anyone from using
# other packages such as Makie, Gadfly etc., given that appropriate `plot_creator`s are
# passed. This is also the reason why the visualization callback is not included via
# Requires.jl only when Plots is present.
# In the future, we should update/remove this warning if other plotting packages are
# starting to be used.
if !(:Plots in names(@__MODULE__, all = true))
@warn "Package `Plots` not loaded but required by `VisualizationCallback` to visualize results"
# Note: This warning is added for convenience, as Plots and Makie are currently the
# only "officially" supported visualization packages. However, in general nothing
# prevents anyone from using other packages, given that appropriate `plot_creator`s are
# passed.

# TODO: rest of this comment?
# This is also the reason why the visualization callback is not included via
# Requires.jl only when Plots is present.
# In the future, we should update/remove this warning if other plotting packages are
# starting to be used.
if !(:Plots in names(@__MODULE__, all = true)) &&
Base.get_extension(Trixi, :TrixiGLMakieExt) === nothing
@warn "Neither `Plots` nor `GLMakie` loaded but required by `VisualizationCallback` to visualize results"
end

DiscreteCallback(visualization_callback, visualization_callback, # the first one is the condition, the second the affect!
Expand Down Expand Up @@ -156,7 +164,7 @@ function (visualization_callback::VisualizationCallback)(integrator)
end

# Create plot
plot_creator(plot_data, variable_names;
plot_creator(visualization_callback, plot_data, variable_names;
show_mesh = show_mesh, plot_arguments = plot_arguments,
time = integrator.t, timestep = integrator.stats.naccept)

Expand All @@ -166,7 +174,7 @@ function (visualization_callback::VisualizationCallback)(integrator)
end

"""
show_plot(plot_data, variable_names;
show_plot(visualization_callback, plot_data, variable_names;
show_mesh=true, plot_arguments=Dict{Symbol,Any}(),
time=nothing, timestep=nothing)

Expand All @@ -182,7 +190,7 @@ This function is the default `plot_creator` argument for the [`VisualizationCall

See also: [`VisualizationCallback`](@ref), [`save_plot`](@ref)
"""
function show_plot(plot_data, variable_names;
function show_plot(visualization_callback, plot_data, variable_names;
show_mesh = true, plot_arguments = Dict{Symbol, Any}(),
time = nothing, timestep = nothing)
# Gather subplots
Expand Down Expand Up @@ -218,7 +226,7 @@ function show_plot(plot_data, variable_names;
end

"""
save_plot(plot_data, variable_names;
save_plot(visualization_callback, plot_data, variable_names;
show_mesh=true, plot_arguments=Dict{Symbol,Any}(),
time=nothing, timestep=nothing)

Expand All @@ -234,7 +242,7 @@ The `timestep` is used in the filename. `time` is currently unused by this funct

See also: [`VisualizationCallback`](@ref), [`show_plot`](@ref)
"""
function save_plot(plot_data, variable_names;
function save_plot(visualization_callback, plot_data, variable_names;
show_mesh = true, plot_arguments = Dict{Symbol, Any}(),
time = nothing, timestep = nothing)
# Gather subplots
Expand All @@ -258,4 +266,8 @@ function save_plot(plot_data, variable_names;
filename = joinpath("out", @sprintf("solution_%09d.png", timestep))
Plots.savefig(filename)
end

# Add definitions of Makie plot functions here such that hey can be exported from Trixi.jl
# and extended in the TrixiGLMakieExt extension
function show_plot_makie end
end # @muladd
Loading