-
Notifications
You must be signed in to change notification settings - Fork 113
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 Makie available in 2D VisualizationCallback #2225
base: main
Are you sure you want to change the base?
Changes from 16 commits
6607023
44db6aa
88e35f7
46feed1
d1a6122
034fa5a
716352e
a81e8dc
24fbffe
d7540dc
9727d3f
2f0562b
5bd1c3a
4d0e9d3
dab3337
b5f8b52
fda5f4f
4d401fa
1fc1d92
72ac1cc
93dd877
bf50f02
8568bec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
|
||
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 100 time steps. | ||
# plot_creator is set to show_plot_makie in order to use the GLMakie backend. | ||
# Additional keyword arguments, such as colorrange, are passed to the respective plotting | ||
# command. | ||
visualization = VisualizationCallback(interval = 100, | ||
plot_creator = Trixi.show_plot_makie, | ||
colorrange = (0.0, 1.0)) | ||
|
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Package extension for adding Makie-based features to Trixi.jl | ||
module TrixiGLMakieExt | ||
|
||
# Required for visualization code | ||
using GLMakie | ||
benegee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Use functions that are to be extended and additional symbols that are not exported | ||
using Trixi: Trixi, @unpack, @muladd, FigureAndAxes | ||
|
||
@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) | ||
benegee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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) | ||
nvars = size(variable_names)[1] | ||
if visualization_callback.figure_axes.fig === nothing | ||
@info "Creating new GLMakie figure" | ||
fig = GLMakie.Figure() | ||
axes = [GLMakie.Axis(fig[makieLayoutHelper(v)...], aspect = DataAspect(), | ||
title = variable_names[v]) | ||
for v in 1:nvars] | ||
if show_mesh | ||
push!(axes, | ||
GLMakie.Axis(fig[makieLayoutHelper(nvars + 1)...], | ||
aspect = DataAspect(), title = "mesh")) | ||
end | ||
visualization_callback.figure_axes = FigureAndAxes(fig, axes) | ||
GLMakie.display(visualization_callback.figure_axes.fig) | ||
end | ||
|
||
@unpack axes = visualization_callback.figure_axes | ||
for v in 1:nvars | ||
GLMakie.heatmap!(axes[v], plot_data.x, plot_data.y, | ||
permutedims(plot_data.data[v]); plot_arguments...) | ||
end | ||
if show_mesh | ||
empty!(axes[nvars + 1]) | ||
lines!(axes[nvars + 1], plot_data.mesh_vertices_x, plot_data.mesh_vertices_y, | ||
color = :black) | ||
end | ||
end | ||
end # @muladd | ||
end # module TrixiGLMakieExt |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,12 @@ | |
@muladd begin | ||
#! format: noindent | ||
|
||
# convenience struct for editing plots after they're created. | ||
struct FigureAndAxes{Figure, Axes} | ||
fig::Figure | ||
axes::Axes | ||
end | ||
|
||
mutable struct VisualizationCallback{SolutionVariables, VariableNames, PlotDataCreator, | ||
PlotCreator} | ||
interval::Int | ||
|
@@ -13,6 +19,7 @@ mutable struct VisualizationCallback{SolutionVariables, VariableNames, PlotDataC | |
show_mesh::Bool | ||
plot_data_creator::PlotDataCreator | ||
plot_creator::PlotCreator | ||
figure_axes::FigureAndAxes | ||
plot_arguments::Dict{Symbol, Any} | ||
end | ||
|
||
|
@@ -99,19 +106,25 @@ function VisualizationCallback(; interval = 0, | |
solution_variables, variable_names, | ||
show_mesh, | ||
plot_data_creator, plot_creator, | ||
FigureAndAxes(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? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be resolved in the merged source code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, definitely! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sloede It's been a while since you added this note. Could you help with updating it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the current status - isn't Plots still using Requires.jl? What do we need to update - isn't this comment still valid? |
||
# 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! | ||
|
@@ -156,7 +169,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) | ||
|
||
|
@@ -166,7 +179,7 @@ function (visualization_callback::VisualizationCallback)(integrator) | |
end | ||
|
||
""" | ||
show_plot(plot_data, variable_names; | ||
show_plot(visualization_callback, plot_data, variable_names; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are changes to documented API, so this is breaking. We should either enable the previous behavior again or include this only in a breaking release. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess nobody is using it actively, but it's documented API. |
||
show_mesh=true, plot_arguments=Dict{Symbol,Any}(), | ||
time=nothing, timestep=nothing) | ||
|
||
|
@@ -182,7 +195,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 | ||
|
@@ -218,7 +231,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) | ||
|
||
|
@@ -234,7 +247,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 | ||
|
@@ -258,4 +271,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 they can be exported from Trixi.jl | ||
# and extended in the TrixiGLMakieExt extension | ||
function show_plot_makie end | ||
end # @muladd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need to be GLMakie.jl, or could it be also one of the other backends?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the 3D case in mind, it would be nice if you could interactively turn your plot around.
But I am not sufficiently familiar with Makie. Can you make the implementation independent of a certain backend?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently that is how it is supposed to work. I feel amazed...
I now removed the GLMakie extension and moved its content to our existing Makie extension. For the added elixir both
using GLMakie
andusing CairoMakie
work (although the latter might not be too useful).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 👍