Path: blob/main/examples/tree_2d_dgsem/elixir_advection_callbacks.jl
2055 views
using OrdinaryDiffEqLowStorageRK1using Trixi23# define new structs inside a module to allow re-evaluating the file4module TrixiExtensionExample56using Trixi7using OrdinaryDiffEqSSPRK: DiscreteCallback, u_modified!89# This is an example implementation for a simple stage callback (i.e., a callable10# that is executed after each Runge-Kutta *stage*), which records some values11# each time it is called. Its sole purpose here is to showcase how to implement12# a stage callback for Trixi.jl.13struct ExampleStageCallback14times::Vector{Float64}15min_values::Vector{Float64}16max_values::Vector{Float64}1718# You can optionally define an inner constructor like the one below to set up19# some required stuff. You can also create outer constructors (not demonstrated20# here) for further customization options.21function ExampleStageCallback()22new(Float64[], Float64[], Float64[])23end24end2526# This method is called when the `ExampleStageCallback` is used as `stage_limiter!`27# which gets called after every RK stage. There is no specific initialization28# method for such `stage_limiter!`s in OrdinaryDiffEq.jl.29function (example_stage_callback::ExampleStageCallback)(u_ode, _, semi, t)30min_val, max_val = extrema(u_ode)31push!(example_stage_callback.times, t)32push!(example_stage_callback.min_values, min_val)33push!(example_stage_callback.max_values, max_val)3435return nothing36end3738# This is an example implementation for a simple step callback (i.e., a callable39# that is potentially executed after each Runge-Kutta *step*), which records40# some values each time it is called. Its sole purpose here is to showcase41# how to implement a step callback for Trixi.jl.42struct ExampleStepCallback43message::String44times::Vector{Float64}45min_values::Vector{Float64}46max_values::Vector{Float64}4748# You can optionally define an inner constructor like the one below to set up49# some required stuff. You can also create outer constructors (not demonstrated50# here) for further customization options.51function ExampleStepCallback(message::String)52new(message, Float64[], Float64[], Float64[])53end54end5556# This method is called when the `ExampleStepCallback` is used as callback57# which gets called after RK steps.58function (example_callback::ExampleStepCallback)(integrator)59u_ode = integrator.u60t = integrator.t61# You can also access semi = integrator.p6263min_val, max_val = extrema(u_ode)64push!(example_callback.times, t)65push!(example_callback.min_values, min_val)66push!(example_callback.max_values, max_val)6768# avoid re-evaluating possible FSAL stages69u_modified!(integrator, false)70return nothing71end7273# This method is used to wrap an `ExampleStepCallback` inside a `DiscreteCallback`74# which gets called after every RK step. You can pass an additional initialization75# method and a separate condition specifying whether the callback shall be called.76function ExampleStepCallback(; message::String)77# Call the `ExampleStepCallback` after every RK step.78condition = (u_ode, t, integrator) -> true7980# You can optionally pass an initialization method. There, you can access the81# `ExampleStepCallback` as `cb.affect!`.82initialize = (cb, u_ode, t, integrator) -> println(cb.affect!.message)8384example_callback = ExampleStepCallback(message)8586DiscreteCallback(condition, example_callback,87save_positions = (false, false),88initialize = initialize)89end9091end # module TrixiExtensionExample9293import .TrixiExtensionExample9495###############################################################################96# semidiscretization of the linear advection equation9798advection_velocity = (0.2, -0.7)99equations = LinearScalarAdvectionEquation2D(advection_velocity)100101initial_condition = initial_condition_convergence_test102solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs)103104coordinates_min = (-1.0, -1.0)105coordinates_max = (1.0, 1.0)106mesh = TreeMesh(coordinates_min, coordinates_max,107initial_refinement_level = 4,108n_cells_max = 30_000)109110semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)111112###############################################################################113# ODE solvers, callbacks etc.114115tspan = (0.0, 1.0)116ode = semidiscretize(semi, tspan)117118summary_callback = SummaryCallback()119120analysis_interval = 100121analysis_callback = AnalysisCallback(semi, interval = analysis_interval,122extra_analysis_integrals = (entropy, energy_total))123124alive_callback = AliveCallback(analysis_interval = analysis_interval)125126save_solution = SaveSolutionCallback(interval = 100,127save_initial_solution = true,128save_final_solution = true,129solution_variables = cons2cons)130131example_callback = TrixiExtensionExample.ExampleStepCallback(message = "Initializing callback")132133stepsize_callback = StepsizeCallback(cfl = 1.6)134135callbacks = CallbackSet(summary_callback,136analysis_callback, alive_callback,137save_solution,138example_callback,139stepsize_callback)140141# In OrdinaryDiffEq.jl, the `step_limiter!` is called after every Runge-Kutta step142# but before possible RHS evaluations of the new value occur. Hence, it's possible143# to modify the new solution value there without impacting the performance of FSAL144# methods.145# The `stage_limiter!` is called after computing a Runge-Kutta stage value but146# before evaluating the corresponding stage derivatives.147# Hence, if a limiter should be called before each RHS evaluation, it needs to be148# set as `stage_limiter!`.149example_stage_callback! = TrixiExtensionExample.ExampleStageCallback()150151###############################################################################152# run the simulation153154sol = solve(ode,155CarpenterKennedy2N54(example_stage_callback!, williamson_condition = false);156dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback157ode_default_options()..., callback = callbacks);158159# Check whether we recorded the same values.160# Remember that CarpenterKennedy2N54 has five stages per step.161@assert example_stage_callback!.times[5:5:end] ≈ example_callback.affect!.times162@assert example_stage_callback!.min_values[5:5:end] ≈ example_callback.affect!.min_values163@assert example_stage_callback!.max_values[5:5:end] ≈ example_callback.affect!.max_values164165166