Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/callbacks_step/save_restart.jl
2802 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
SaveRestartCallback(; interval=0,
10
save_final_restart=true,
11
output_directory="out")
12
13
Save the current numerical solution in a restart file every `interval` time steps.
14
"""
15
struct SaveRestartCallback
16
interval::Int
17
save_final_restart::Bool
18
output_directory::String
19
end
20
21
function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:SaveRestartCallback})
22
@nospecialize cb # reduce precompilation time
23
24
restart_callback = cb.affect!
25
print(io, "SaveRestartCallback(interval=", restart_callback.interval, ")")
26
return nothing
27
end
28
29
function Base.show(io::IO, ::MIME"text/plain",
30
cb::DiscreteCallback{<:Any, <:SaveRestartCallback})
31
@nospecialize cb # reduce precompilation time
32
33
if get(io, :compact, false)
34
show(io, cb)
35
else
36
save_restart_callback = cb.affect!
37
38
setup = [
39
"interval" => save_restart_callback.interval,
40
"save final solution" => save_restart_callback.save_final_restart ? "yes" :
41
"no",
42
"output directory" => abspath(normpath(save_restart_callback.output_directory))
43
]
44
summary_box(io, "SaveRestartCallback", setup)
45
end
46
end
47
48
function SaveRestartCallback(; interval = 0,
49
save_final_restart = true,
50
output_directory = "out")
51
restart_callback = SaveRestartCallback(interval, save_final_restart,
52
output_directory)
53
54
return DiscreteCallback(restart_callback, restart_callback, # the first one is the condition, the second the affect!
55
save_positions = (false, false),
56
initialize = initialize!)
57
end
58
59
function initialize!(cb::DiscreteCallback{Condition, Affect!}, u, t,
60
integrator) where {Condition, Affect! <: SaveRestartCallback}
61
restart_callback = cb.affect!
62
63
mpi_isroot() && mkpath(restart_callback.output_directory)
64
65
semi = integrator.p
66
67
@trixi_timeit timer() "I/O" begin
68
save_mesh(semi, restart_callback.output_directory)
69
end
70
71
return nothing
72
end
73
74
# this method is called to determine whether the callback should be activated
75
function (restart_callback::SaveRestartCallback)(u, t, integrator)
76
@unpack interval, save_final_restart = restart_callback
77
78
# With error-based step size control, some steps can be rejected. Thus,
79
# `integrator.iter >= integrator.stats.naccept`
80
# (total #steps) (#accepted steps)
81
# We need to check the number of accepted steps since callbacks are not
82
# activated after a rejected step.
83
return interval > 0 && (integrator.stats.naccept % interval == 0 ||
84
(save_final_restart && isfinished(integrator)))
85
end
86
87
# this method is called when the callback is activated
88
function (restart_callback::SaveRestartCallback)(integrator)
89
u_ode = integrator.u
90
@unpack t, dt = integrator
91
iter = integrator.stats.naccept
92
semi = integrator.p
93
94
@trixi_timeit timer() "I/O" begin
95
save_mesh(semi, restart_callback.output_directory, iter)
96
save_restart_file(u_ode, t, dt, iter, semi, restart_callback)
97
# If using an adaptive time stepping scheme, store controller values for restart
98
if integrator.opts.adaptive
99
save_adaptive_time_integrator(integrator, integrator.opts.controller,
100
restart_callback)
101
end
102
end
103
104
# avoid re-evaluating possible FSAL stages
105
u_modified!(integrator, false)
106
return nothing
107
end
108
109
@inline function save_restart_file(u_ode, t, dt, iter,
110
semi::AbstractSemidiscretization, restart_callback)
111
mesh, equations, solver, cache = mesh_equations_solver_cache(semi)
112
u = wrap_array_native(u_ode, mesh, equations, solver, cache)
113
return save_restart_file(u, t, dt, iter, mesh, equations, solver, cache,
114
restart_callback)
115
end
116
117
"""
118
load_time(restart_file::AbstractString)
119
120
Load the time saved in a `restart_file`.
121
"""
122
function load_time(restart_file::AbstractString)
123
h5open(restart_file, "r") do file
124
return read(attributes(file)["time"])
125
end
126
end
127
128
"""
129
load_timestep(restart_file::AbstractString)
130
131
Load the time step number (`iter` in OrdinaryDiffEq.jl) saved in a `restart_file`.
132
"""
133
function load_timestep(restart_file::AbstractString)
134
h5open(restart_file, "r") do file
135
return read(attributes(file)["timestep"])
136
end
137
end
138
139
"""
140
load_timestep!(integrator, restart_file::AbstractString)
141
142
Load the time step number saved in a `restart_file` and assign it to both the time step
143
number and and the number of accepted steps
144
(`iter` and `stats.naccept` in OrdinaryDiffEq.jl, respectively) in `integrator`.
145
"""
146
function load_timestep!(integrator, restart_file::AbstractString)
147
integrator.iter = load_timestep(restart_file)
148
return integrator.stats.naccept = integrator.iter
149
end
150
151
"""
152
load_dt(restart_file::AbstractString)
153
154
Load the time step size (`dt` in OrdinaryDiffEq.jl) saved in a `restart_file`.
155
"""
156
function load_dt(restart_file::AbstractString)
157
h5open(restart_file, "r") do file
158
return read(attributes(file)["dt"])
159
end
160
end
161
162
function load_restart_file(semi::AbstractSemidiscretization, restart_file)
163
return load_restart_file(mesh_equations_solver_cache(semi)..., restart_file)
164
end
165
166
"""
167
load_adaptive_time_integrator!(integrator, restart_file::AbstractString)
168
169
Load the context information for time integrators with error-based step size control
170
saved in a `restart_file`.
171
"""
172
function load_adaptive_time_integrator!(integrator, restart_file::AbstractString)
173
controller = integrator.opts.controller
174
# Read context information for controller
175
h5open(restart_file, "r") do file
176
# Ensure that the necessary information was saved
177
if !("time_integrator_qold" in keys(attributes(file))) ||
178
!("time_integrator_dtpropose" in keys(attributes(file))) ||
179
(hasproperty(controller, :err) &&
180
!("time_integrator_controller_err" in keys(attributes(file))))
181
error("Missing data in restart file: check the consistency of adaptive time controller with initial setup!")
182
end
183
# Load data that is required both for PIController and PIDController
184
integrator.qold = read(attributes(file)["time_integrator_qold"])
185
integrator.dtpropose = read(attributes(file)["time_integrator_dtpropose"])
186
# Accept step to use dtpropose already in the first step
187
integrator.accept_step = true
188
# Reevaluate integrator.fsal_first on the first step
189
integrator.reeval_fsal = true
190
# Load additional parameters for PIDController
191
if hasproperty(controller, :err) # Distinguish PIDController from PIController
192
controller.err[:] = read(attributes(file)["time_integrator_controller_err"])
193
end
194
end
195
end
196
197
include("save_restart_dg.jl")
198
end # @muladd
199
200