Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/examples/tree_2d_dgsem/elixir_advection_callbacks.jl
2055 views
1
using OrdinaryDiffEqLowStorageRK
2
using Trixi
3
4
# define new structs inside a module to allow re-evaluating the file
5
module TrixiExtensionExample
6
7
using Trixi
8
using OrdinaryDiffEqSSPRK: DiscreteCallback, u_modified!
9
10
# This is an example implementation for a simple stage callback (i.e., a callable
11
# that is executed after each Runge-Kutta *stage*), which records some values
12
# each time it is called. Its sole purpose here is to showcase how to implement
13
# a stage callback for Trixi.jl.
14
struct ExampleStageCallback
15
times::Vector{Float64}
16
min_values::Vector{Float64}
17
max_values::Vector{Float64}
18
19
# You can optionally define an inner constructor like the one below to set up
20
# some required stuff. You can also create outer constructors (not demonstrated
21
# here) for further customization options.
22
function ExampleStageCallback()
23
new(Float64[], Float64[], Float64[])
24
end
25
end
26
27
# This method is called when the `ExampleStageCallback` is used as `stage_limiter!`
28
# which gets called after every RK stage. There is no specific initialization
29
# method for such `stage_limiter!`s in OrdinaryDiffEq.jl.
30
function (example_stage_callback::ExampleStageCallback)(u_ode, _, semi, t)
31
min_val, max_val = extrema(u_ode)
32
push!(example_stage_callback.times, t)
33
push!(example_stage_callback.min_values, min_val)
34
push!(example_stage_callback.max_values, max_val)
35
36
return nothing
37
end
38
39
# This is an example implementation for a simple step callback (i.e., a callable
40
# that is potentially executed after each Runge-Kutta *step*), which records
41
# some values each time it is called. Its sole purpose here is to showcase
42
# how to implement a step callback for Trixi.jl.
43
struct ExampleStepCallback
44
message::String
45
times::Vector{Float64}
46
min_values::Vector{Float64}
47
max_values::Vector{Float64}
48
49
# You can optionally define an inner constructor like the one below to set up
50
# some required stuff. You can also create outer constructors (not demonstrated
51
# here) for further customization options.
52
function ExampleStepCallback(message::String)
53
new(message, Float64[], Float64[], Float64[])
54
end
55
end
56
57
# This method is called when the `ExampleStepCallback` is used as callback
58
# which gets called after RK steps.
59
function (example_callback::ExampleStepCallback)(integrator)
60
u_ode = integrator.u
61
t = integrator.t
62
# You can also access semi = integrator.p
63
64
min_val, max_val = extrema(u_ode)
65
push!(example_callback.times, t)
66
push!(example_callback.min_values, min_val)
67
push!(example_callback.max_values, max_val)
68
69
# avoid re-evaluating possible FSAL stages
70
u_modified!(integrator, false)
71
return nothing
72
end
73
74
# This method is used to wrap an `ExampleStepCallback` inside a `DiscreteCallback`
75
# which gets called after every RK step. You can pass an additional initialization
76
# method and a separate condition specifying whether the callback shall be called.
77
function ExampleStepCallback(; message::String)
78
# Call the `ExampleStepCallback` after every RK step.
79
condition = (u_ode, t, integrator) -> true
80
81
# You can optionally pass an initialization method. There, you can access the
82
# `ExampleStepCallback` as `cb.affect!`.
83
initialize = (cb, u_ode, t, integrator) -> println(cb.affect!.message)
84
85
example_callback = ExampleStepCallback(message)
86
87
DiscreteCallback(condition, example_callback,
88
save_positions = (false, false),
89
initialize = initialize)
90
end
91
92
end # module TrixiExtensionExample
93
94
import .TrixiExtensionExample
95
96
###############################################################################
97
# semidiscretization of the linear advection equation
98
99
advection_velocity = (0.2, -0.7)
100
equations = LinearScalarAdvectionEquation2D(advection_velocity)
101
102
initial_condition = initial_condition_convergence_test
103
solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs)
104
105
coordinates_min = (-1.0, -1.0)
106
coordinates_max = (1.0, 1.0)
107
mesh = TreeMesh(coordinates_min, coordinates_max,
108
initial_refinement_level = 4,
109
n_cells_max = 30_000)
110
111
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver)
112
113
###############################################################################
114
# ODE solvers, callbacks etc.
115
116
tspan = (0.0, 1.0)
117
ode = semidiscretize(semi, tspan)
118
119
summary_callback = SummaryCallback()
120
121
analysis_interval = 100
122
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
123
extra_analysis_integrals = (entropy, energy_total))
124
125
alive_callback = AliveCallback(analysis_interval = analysis_interval)
126
127
save_solution = SaveSolutionCallback(interval = 100,
128
save_initial_solution = true,
129
save_final_solution = true,
130
solution_variables = cons2cons)
131
132
example_callback = TrixiExtensionExample.ExampleStepCallback(message = "Initializing callback")
133
134
stepsize_callback = StepsizeCallback(cfl = 1.6)
135
136
callbacks = CallbackSet(summary_callback,
137
analysis_callback, alive_callback,
138
save_solution,
139
example_callback,
140
stepsize_callback)
141
142
# In OrdinaryDiffEq.jl, the `step_limiter!` is called after every Runge-Kutta step
143
# but before possible RHS evaluations of the new value occur. Hence, it's possible
144
# to modify the new solution value there without impacting the performance of FSAL
145
# methods.
146
# The `stage_limiter!` is called after computing a Runge-Kutta stage value but
147
# before evaluating the corresponding stage derivatives.
148
# Hence, if a limiter should be called before each RHS evaluation, it needs to be
149
# set as `stage_limiter!`.
150
example_stage_callback! = TrixiExtensionExample.ExampleStageCallback()
151
152
###############################################################################
153
# run the simulation
154
155
sol = solve(ode,
156
CarpenterKennedy2N54(example_stage_callback!, williamson_condition = false);
157
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
158
ode_default_options()..., callback = callbacks);
159
160
# Check whether we recorded the same values.
161
# Remember that CarpenterKennedy2N54 has five stages per step.
162
@assert example_stage_callback!.times[5:5:end] example_callback.affect!.times
163
@assert example_stage_callback!.min_values[5:5:end] example_callback.affect!.min_values
164
@assert example_stage_callback!.max_values[5:5:end] example_callback.affect!.max_values
165
166