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