Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/callbacks_step/stepsize.jl
2055 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
"""
9
StepsizeCallback(; cfl=1.0, interval = 1)
10
11
Set the time step size according to a CFL condition with CFL number `cfl`
12
if the time integration method isn't adaptive itself.
13
14
The supplied keyword argument `cfl` must be either a `Real` number or
15
a function of time `t` returning a `Real` number.
16
By default, the timestep will be adjusted at every step.
17
For different values of `interval`, the timestep will be adjusted every `interval` steps.
18
"""
19
mutable struct StepsizeCallback{CflType}
20
cfl_number::CflType
21
interval::Int
22
end
23
24
function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:StepsizeCallback})
25
@nospecialize cb # reduce precompilation time
26
27
stepsize_callback = cb.affect!
28
@unpack cfl_number, interval = stepsize_callback
29
print(io, "StepsizeCallback(",
30
"cfl_number=", cfl_number, ", ",
31
"interval=", interval, ")")
32
end
33
34
function Base.show(io::IO, ::MIME"text/plain",
35
cb::DiscreteCallback{<:Any, <:StepsizeCallback})
36
@nospecialize cb # reduce precompilation time
37
38
if get(io, :compact, false)
39
show(io, cb)
40
else
41
stepsize_callback = cb.affect!
42
43
setup = ["CFL number" => stepsize_callback.cfl_number
44
"Interval" => stepsize_callback.interval]
45
summary_box(io, "StepsizeCallback", setup)
46
end
47
end
48
49
function StepsizeCallback(; cfl = 1.0, interval = 1)
50
stepsize_callback = StepsizeCallback{typeof(cfl)}(cfl, interval)
51
52
DiscreteCallback(stepsize_callback, stepsize_callback, # the first one is the condition, the second the affect!
53
save_positions = (false, false),
54
initialize = initialize!)
55
end
56
57
# Compatibility constructor
58
function StepsizeCallback(cfl)
59
StepsizeCallback{typeof(cfl)}(cfl, 1)
60
end
61
62
function initialize!(cb::DiscreteCallback{Condition, Affect!}, u, t,
63
integrator) where {Condition, Affect! <: StepsizeCallback}
64
cb.affect!(integrator)
65
end
66
67
# this method is called to determine whether the callback should be activated
68
function (stepsize_callback::StepsizeCallback)(u, t, integrator)
69
@unpack interval = stepsize_callback
70
71
# Although the CFL-based timestep is usually not used with
72
# adaptive time integration methods, we still check the accepted steps `naccept` here.
73
return interval > 0 && integrator.stats.naccept % interval == 0
74
end
75
76
# This method is called as callback during the time integration.
77
@inline function (stepsize_callback::StepsizeCallback)(integrator)
78
if integrator.opts.adaptive
79
throw(ArgumentError("The `StepsizeCallback` has no effect when using an adaptive time integration scheme. Please remove the `StepsizeCallback` or set `adaptive = false` in `solve`."))
80
end
81
82
t = integrator.t
83
u_ode = integrator.u
84
semi = integrator.p
85
@unpack cfl_number = stepsize_callback
86
87
# Dispatch based on semidiscretization
88
dt = @trixi_timeit timer() "calculate dt" calculate_dt(u_ode, t, cfl_number, semi)
89
90
set_proposed_dt!(integrator, dt)
91
integrator.opts.dtmax = dt
92
integrator.dtcache = dt
93
94
# avoid re-evaluating possible FSAL stages
95
u_modified!(integrator, false)
96
return nothing
97
end
98
99
# Time integration methods from the DiffEq ecosystem without adaptive time stepping on their own
100
# such as `CarpenterKennedy2N54` require passing `dt=...` in `solve(ode, ...)`. Since we don't have
101
# an integrator at this stage but only the ODE, this method will be used there. It's called in
102
# many examples in `solve(ode, ..., dt=stepsize_callback(ode), ...)`.
103
function (cb::DiscreteCallback{Condition, Affect!})(ode::ODEProblem) where {Condition,
104
Affect! <:
105
StepsizeCallback
106
}
107
stepsize_callback = cb.affect!
108
@unpack cfl_number = stepsize_callback
109
u_ode = ode.u0
110
t = first(ode.tspan)
111
semi = ode.p
112
113
dt = calculate_dt(u_ode, t, cfl_number, semi)
114
end
115
116
# General case for a single (i.e., non-coupled) semidiscretization
117
# Case for constant `cfl_number`.
118
function calculate_dt(u_ode, t, cfl_number::Real, semi::AbstractSemidiscretization)
119
mesh, equations, solver, cache = mesh_equations_solver_cache(semi)
120
u = wrap_array(u_ode, mesh, equations, solver, cache)
121
122
dt = cfl_number * max_dt(u, t, mesh,
123
have_constant_speed(equations), equations,
124
solver, cache)
125
end
126
# Case for `cfl_number` as a function of time `t`.
127
function calculate_dt(u_ode, t, cfl_number, semi::AbstractSemidiscretization)
128
mesh, equations, solver, cache = mesh_equations_solver_cache(semi)
129
u = wrap_array(u_ode, mesh, equations, solver, cache)
130
131
dt = cfl_number(t) * max_dt(u, t, mesh,
132
have_constant_speed(equations), equations,
133
solver, cache)
134
end
135
136
include("stepsize_dg1d.jl")
137
include("stepsize_dg2d.jl")
138
include("stepsize_dg3d.jl")
139
end # @muladd
140
141