Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/ext/TrixiConvexECOSExt.jl
2055 views
1
# Package extension for adding Convex-based features to Trixi.jl
2
module TrixiConvexECOSExt
3
4
# Required for coefficient optimization in PERK scheme integrators
5
using Convex: MOI, solve!, Variable, minimize, evaluate
6
using ECOS: Optimizer
7
8
# Use other necessary libraries
9
using LinearAlgebra: eigvals
10
11
# Use functions that are to be extended and additional symbols that are not exported
12
using Trixi: Trixi, bisect_stability_polynomial, @muladd
13
14
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
15
# Since these FMAs can increase the performance of many numerical algorithms,
16
# we need to opt-in explicitly.
17
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
18
@muladd begin
19
#! format: noindent
20
21
# Undo normalization of stability polynomial coefficients by index factorial
22
# relative to consistency order.
23
function undo_normalization!(gamma_opt, num_stage_evals,
24
num_reduced_coeffs, fac_offset)
25
for k in 1:(num_stage_evals - num_reduced_coeffs)
26
gamma_opt[k] /= factorial(k + fac_offset)
27
end
28
end
29
30
@inline function polynomial_exponential_terms!(pnoms, normalized_powered_eigvals_scaled,
31
consistency_order)
32
# Initialize with zero'th order (z^0) coefficient
33
pnoms .= 1
34
35
# First `consistency_order` terms of the exponential
36
for k in 1:consistency_order
37
pnoms .+= view(normalized_powered_eigvals_scaled, :, k)
38
end
39
40
return nothing
41
end
42
43
# Compute stability polynomials for paired explicit Runge-Kutta up to specified consistency
44
# order, including contributions from free coefficients for higher orders, and
45
# return the maximum absolute value
46
function stability_polynomials!(pnoms, num_stage_evals,
47
normalized_powered_eigvals_scaled,
48
gamma, consistency_order,
49
num_reduced_unknown; kwargs...)
50
polynomial_exponential_terms!(pnoms, normalized_powered_eigvals_scaled,
51
consistency_order)
52
if consistency_order == 4
53
cS3 = kwargs[:cS3]
54
# Constants arising from the particular form of Butcher tableau chosen for the 4th order PERK methods
55
# cS3 = c_{S-3}
56
k1 = 0.001055026310046423 / cS3
57
k2 = 0.03726406530405851 / cS3
58
59
# "Fixed" term due to choice of the PERK4 Butcher tableau
60
# Required to un-do the normalization of the eigenvalues here
61
pnoms += k1 * view(normalized_powered_eigvals_scaled, :, 5) * factorial(5)
62
63
# Contribution from free coefficients
64
for k in 1:(num_stage_evals - 5)
65
pnoms += (k2 * view(normalized_powered_eigvals_scaled, :, k + 4) *
66
gamma[k] +
67
k1 * view(normalized_powered_eigvals_scaled, :, k + 5) *
68
gamma[k] * (k + 5)) # Ensure same normalization of both summands
69
end
70
else
71
# Contribution from free coefficients
72
for k in (consistency_order + 1):num_stage_evals
73
pnoms += gamma[k - consistency_order] *
74
view(normalized_powered_eigvals_scaled, :, k)
75
end
76
end
77
78
# For optimization only the maximum is relevant
79
if num_stage_evals - num_reduced_unknown == 0
80
return maximum(abs.(pnoms)) # If there is no variable to optimize, we need to use the broadcast operator.
81
else
82
return maximum(abs(pnoms))
83
end
84
end
85
86
@inline function normalize_power_eigvals!(normalized_powered_eigvals,
87
eig_vals,
88
num_stage_evals)
89
for j in 1:num_stage_evals
90
@views normalized_powered_eigvals[:, j] = eig_vals[:] .^ j ./ factorial(j)
91
end
92
end
93
94
#=
95
The following structures and methods provide a simplified implementation to
96
discover optimal stability polynomial for a given set of `eig_vals`
97
These are designed for the one-step (i.e., Runge-Kutta methods) integration of initial value ordinary
98
and partial differential equations.
99
100
- Ketcheson and Ahmadia (2012).
101
Optimal stability polynomials for numerical integration of initial value problems
102
[DOI: 10.2140/camcos.2012.7.247](https://doi.org/10.2140/camcos.2012.7.247)
103
104
For the fourth-order PERK schemes, a specialized optimization routine is required, see
105
- D. Doehring, L. Christmann, M. Schlottke-Lakemper, G. J. Gassner and M. Torrilhon (2024).
106
Fourth-Order Paired-Explicit Runge-Kutta Methods
107
[DOI:10.48550/arXiv.2408.05470](https://doi.org/10.48550/arXiv.2408.05470)
108
=#
109
110
# Perform bisection to optimize timestep for stability of the polynomial
111
function Trixi.bisect_stability_polynomial(consistency_order, num_eig_vals,
112
num_stage_evals,
113
dtmax, dteps, eig_vals;
114
kwargs...)
115
dtmin = 0.0
116
dt = -1.0
117
abs_p = -1.0
118
119
if consistency_order == 4
120
# Fourth-order scheme has one additional fixed coefficient
121
num_reduced_unknown = 5
122
else # p = 2, 3
123
num_reduced_unknown = consistency_order
124
end
125
126
# Construct stability polynomial for each eigenvalue
127
pnoms = ones(Complex{Float64}, num_eig_vals, 1)
128
129
# Init datastructure for monomial coefficients
130
gamma = Variable(num_stage_evals - num_reduced_unknown)
131
132
normalized_powered_eigvals = zeros(Complex{Float64}, num_eig_vals, num_stage_evals)
133
normalize_power_eigvals!(normalized_powered_eigvals,
134
eig_vals,
135
num_stage_evals)
136
137
normalized_powered_eigvals_scaled = similar(normalized_powered_eigvals)
138
139
if kwargs[:verbose]
140
println("Start optimization of stability polynomial \n")
141
end
142
143
# Bisection on timestep
144
while dtmax - dtmin > dteps
145
dt = 0.5 * (dtmax + dtmin)
146
147
for k in 1:num_stage_evals
148
@views normalized_powered_eigvals_scaled[:, k] = dt^k .*
149
normalized_powered_eigvals[:,
150
k]
151
end
152
153
# Check if there are variables to optimize
154
if num_stage_evals - num_reduced_unknown > 0
155
# Use last optimal values for gamma in (potentially) next iteration
156
problem = minimize(stability_polynomials!(pnoms,
157
num_stage_evals,
158
normalized_powered_eigvals_scaled,
159
gamma, consistency_order,
160
num_reduced_unknown; kwargs...))
161
162
solve!(problem,
163
# Parameters taken from default values for EiCOS
164
MOI.OptimizerWithAttributes(Optimizer, "gamma" => 0.99,
165
"delta" => 2e-7,
166
"feastol" => 1e-9,
167
"abstol" => 1e-9,
168
"reltol" => 1e-9,
169
"feastol_inacc" => 1e-4,
170
"abstol_inacc" => 5e-5,
171
"reltol_inacc" => 5e-5,
172
"nitref" => 9,
173
"maxit" => 100,
174
"verbose" => 3); silent = true)
175
176
abs_p = problem.optval
177
else
178
abs_p = stability_polynomials!(pnoms,
179
num_stage_evals,
180
normalized_powered_eigvals_scaled,
181
gamma, consistency_order,
182
num_reduced_unknown; kwargs...)
183
end
184
185
if abs_p < 1
186
dtmin = dt
187
else
188
dtmax = dt
189
end
190
end
191
192
if kwargs[:verbose]
193
println("Concluded stability polynomial optimization \n")
194
end
195
196
if num_stage_evals - num_reduced_unknown > 0
197
gamma_opt = evaluate(gamma)
198
199
# Catch case with only one optimization variable
200
if isa(gamma_opt, Number)
201
gamma_opt = [gamma_opt]
202
end
203
else
204
gamma_opt = nothing # If there is no variable to optimize, return gamma_opt as nothing.
205
end
206
207
undo_normalization!(gamma_opt, num_stage_evals,
208
num_reduced_unknown, consistency_order)
209
210
return gamma_opt, dt
211
end
212
end # @muladd
213
214
end # module TrixiConvexECOSExt
215
216