Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/test/test_special_elixirs.jl
5582 views
1
module TestElixirs
2
3
using LinearAlgebra
4
using SparseArrays
5
using Test
6
using Trixi
7
using OrdinaryDiffEqSSPRK: SSPRK43
8
9
import ForwardDiff
10
11
include("test_trixi.jl")
12
13
# Start with a clean environment: remove Trixi.jl output directory if it exists
14
outdir = "out"
15
isdir(outdir) && rm(outdir, recursive = true)
16
17
EXAMPLES_DIR = examples_dir()
18
19
@testset "Special elixirs" begin
20
#! format: noindent
21
22
@testset "Convergence test" begin
23
@timed_testset "tree_2d_dgsem" begin
24
eocs, _ = convergence_test(@__MODULE__,
25
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
26
"elixir_advection_extended.jl"),
27
3, initial_refinement_level = 2)
28
mean_convergence = Trixi.calc_mean_convergence(eocs)
29
@test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05)
30
end
31
32
@timed_testset "structured_2d_dgsem" begin
33
eocs, _ = convergence_test(@__MODULE__,
34
joinpath(EXAMPLES_DIR,
35
"structured_2d_dgsem",
36
"elixir_advection_extended.jl"),
37
3, cells_per_dimension = (5, 9))
38
mean_convergence = Trixi.calc_mean_convergence(eocs)
39
@test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05)
40
end
41
42
@timed_testset "structured_2d_dgsem coupled" begin
43
eocs, _ = convergence_test(@__MODULE__,
44
joinpath(EXAMPLES_DIR,
45
"structured_2d_dgsem",
46
"elixir_advection_coupled.jl"),
47
3)
48
for i in Trixi.eachsystem(semi)
49
mean_convergence = Trixi.calc_mean_convergence(eocs[i])
50
@test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05)
51
@test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05)
52
end
53
end
54
55
@timed_testset "p4est_2d_dgsem" begin
56
# Run convergence test on unrefined mesh
57
no_refine = @cfunction((p4est, which_tree, quadrant)->Cint(0), Cint,
58
(Ptr{Trixi.p4est_t}, Ptr{Trixi.p4est_topidx_t},
59
Ptr{Trixi.p4est_quadrant_t}))
60
eocs, _ = convergence_test(@__MODULE__,
61
joinpath(EXAMPLES_DIR, "p4est_2d_dgsem",
62
"elixir_euler_source_terms_nonconforming_unstructured_flag.jl"),
63
2, refine_fn_c = no_refine)
64
mean_convergence = Trixi.calc_mean_convergence(eocs)
65
@test isapprox(mean_convergence[:linf], [3.2, 3.2, 4.0, 3.7], rtol = 0.05)
66
end
67
68
@timed_testset "structured_3d_dgsem" begin
69
eocs, _ = convergence_test(@__MODULE__,
70
joinpath(EXAMPLES_DIR,
71
"structured_3d_dgsem",
72
"elixir_advection_basic.jl"),
73
2, cells_per_dimension = (7, 4, 5))
74
mean_convergence = Trixi.calc_mean_convergence(eocs)
75
@test isapprox(mean_convergence[:l2], [4.0], rtol = 0.05)
76
end
77
78
@timed_testset "p4est_3d_dgsem" begin
79
eocs, _ = convergence_test(@__MODULE__,
80
joinpath(EXAMPLES_DIR, "p4est_3d_dgsem",
81
"elixir_advection_unstructured_curved.jl"),
82
2, initial_refinement_level = 0)
83
mean_convergence = Trixi.calc_mean_convergence(eocs)
84
@test isapprox(mean_convergence[:l2], [2.7], rtol = 0.05)
85
end
86
87
@timed_testset "paper_self_gravitating_gas_dynamics" begin
88
eocs, _ = convergence_test(@__MODULE__,
89
joinpath(EXAMPLES_DIR,
90
"paper_self_gravitating_gas_dynamics",
91
"elixir_eulergravity_convergence.jl"),
92
2, tspan = (0.0, 0.25),
93
initial_refinement_level = 1)
94
mean_convergence = Trixi.calc_mean_convergence(eocs)
95
@test isapprox(mean_convergence[:l2], 4 * ones(4), atol = 0.4)
96
end
97
end
98
99
@timed_testset "Test linear structure (2D)" begin
100
trixi_include(@__MODULE__,
101
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
102
"elixir_advection_extended.jl"),
103
tspan = (0.0, 0.0), initial_refinement_level = 2)
104
A, b = linear_structure(semi)
105
λ = eigvals(Matrix(A))
106
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
107
108
trixi_include(@__MODULE__,
109
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
110
"elixir_hypdiff_lax_friedrichs.jl"),
111
tspan = (0.0, 0.0), initial_refinement_level = 2)
112
A, b = linear_structure(semi)
113
λ = eigvals(Matrix(A))
114
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
115
116
# check whether the user can modify `b` without changing `A`
117
x = vec(ode.u0)
118
Ax = A * x
119
@. b = 2 * b + x
120
@test A * x Ax
121
end
122
123
@testset "Test Jacobian of DG (1D)" begin
124
@timed_testset "TreeMesh: Linear advection" begin
125
trixi_include(@__MODULE__,
126
joinpath(EXAMPLES_DIR, "tree_1d_fdsbp",
127
"elixir_advection_upwind.jl"),
128
tspan = (0.0, 0.0))
129
130
A, _ = linear_structure(semi)
131
132
J = jacobian_ad_forward(semi)
133
@test Matrix(A) J
134
λ = eigvals(J)
135
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
136
137
J = jacobian_fd(semi)
138
@test Matrix(A) J
139
λ = eigvals(J)
140
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
141
142
# See https://github.com/trixi-framework/Trixi.jl/pull/2514
143
@test count(real.(λ) .>= -10) > 5
144
# See https://github.com/trixi-framework/Trixi.jl/pull/2522
145
t0 = zero(real(semi))
146
u0_ode = 1e9 * compute_coefficients(t0, semi)
147
J = jacobian_fd(semi; t0, u0_ode)
148
λ = eigvals(J)
149
@test count((-200 .<= real.(λ) .<= -10) .&& (-100 .<= imag.(λ) .<= 100)) == 0
150
@test count(isapprox.(imag.(λ), 0.0, atol = 10 * sqrt(eps(real(semi))))) == 2
151
end
152
153
@timed_testset "StructuredMesh: Compressible Euler equations" begin
154
trixi_include(@__MODULE__,
155
joinpath(EXAMPLES_DIR, "structured_1d_dgsem",
156
"elixir_euler_source_terms.jl"),
157
tspan = (0.0, 0.0))
158
159
J = jacobian_ad_forward(semi)
160
λ = eigvals(J)
161
@test maximum(real, λ) < 1e-13
162
163
J = jacobian_fd(semi)
164
λ = eigvals(J)
165
@test maximum(real, λ) < 5e-8
166
end
167
end
168
169
@testset "Test Jacobian of DG (2D)" begin
170
@timed_testset "TreeMesh: Linear advection" begin
171
trixi_include(@__MODULE__,
172
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
173
"elixir_advection_extended.jl"),
174
tspan = (0.0, 0.0), initial_refinement_level = 2)
175
A, _ = linear_structure(semi)
176
177
J = jacobian_ad_forward(semi)
178
@test Matrix(A) J
179
λ = eigvals(J)
180
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
181
182
J = jacobian_fd(semi)
183
@test Matrix(A) J
184
λ = eigvals(J)
185
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
186
end
187
188
@timed_testset "TreeMesh: Linear advection-diffusion" begin
189
trixi_include(@__MODULE__,
190
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
191
"elixir_advection_diffusion.jl"),
192
tspan = (0.0, 0.0), initial_refinement_level = 2)
193
194
J = jacobian_ad_forward(semi)
195
λ = eigvals(J)
196
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
197
198
A, b = linear_structure(semi)
199
@test Matrix(A) == J
200
@test sparse(A) == sparse(J)
201
# Ensure that we do not have excessive memory allocations
202
# (e.g., from type instabilities)
203
du = zero(b)
204
u = zero(b)
205
mul!(du, A, u) # compilation run
206
@test (@allocated mul!(du, A, u)) == 0
207
208
J_parabolic = jacobian_ad_forward_parabolic(semi)
209
λ_parabolic = eigvals(J_parabolic)
210
# Parabolic spectrum is real and negative
211
@test maximum(real, λ_parabolic) < 2 * 10^(-14)
212
@test maximum(imag, λ_parabolic) < 10^(-14)
213
end
214
215
@timed_testset "TreeMesh: Compressible Euler equations" begin
216
trixi_include(@__MODULE__,
217
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
218
"elixir_euler_density_wave.jl"),
219
tspan = (0.0, 0.0), initial_refinement_level = 1)
220
221
J = jacobian_ad_forward(semi)
222
λ = eigvals(J)
223
@test maximum(real, λ) < 7.0e-7
224
225
J = jacobian_fd(semi)
226
λ = eigvals(J)
227
@test maximum(real, λ) < 7.0e-3
228
229
# This does not work yet because of the indicators...
230
@test_skip begin
231
trixi_include(@__MODULE__,
232
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
233
"elixir_euler_shockcapturing.jl"),
234
tspan = (0.0, 0.0), initial_refinement_level = 1)
235
jacobian_ad_forward(semi)
236
end
237
238
@timed_testset "DGMulti: Euler, weak form" begin
239
equations = CompressibleEulerEquations2D(1.4)
240
initial_condition = initial_condition_density_wave
241
242
solver = DGMulti(polydeg = 5, element_type = Quad(),
243
approximation_type = SBP(),
244
surface_integral = SurfaceIntegralWeakForm(flux_central),
245
volume_integral = VolumeIntegralWeakForm())
246
247
# DGMultiMesh is on [-1, 1]^ndims by default
248
cells_per_dimension = (2, 2)
249
mesh = DGMultiMesh(solver, cells_per_dimension,
250
periodicity = (true, true))
251
252
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition,
253
solver;
254
boundary_conditions = boundary_condition_periodic)
255
256
J = jacobian_ad_forward(semi)
257
λ = eigvals(J)
258
@test maximum(real, λ) < 7.0e-7
259
end
260
261
@timed_testset "DGMulti: Euler, SBP & flux differencing" begin
262
equations = CompressibleEulerEquations2D(1.4)
263
initial_condition = initial_condition_density_wave
264
265
solver = DGMulti(polydeg = 5, element_type = Quad(),
266
approximation_type = SBP(),
267
surface_integral = SurfaceIntegralWeakForm(flux_central),
268
volume_integral = VolumeIntegralFluxDifferencing(flux_central))
269
270
# DGMultiMesh is on [-1, 1]^ndims by default
271
cells_per_dimension = (2, 2)
272
mesh = DGMultiMesh(solver, cells_per_dimension,
273
periodicity = (true, true))
274
275
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition,
276
solver;
277
boundary_conditions = boundary_condition_periodic)
278
279
J = jacobian_ad_forward(semi)
280
λ = eigvals(J)
281
@test maximum(real, λ) < 7.0e-7
282
end
283
end
284
285
@timed_testset "TreeMesh: Navier-Stokes" begin
286
trixi_include(@__MODULE__,
287
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
288
"elixir_navierstokes_taylor_green_vortex.jl"),
289
tspan = (0.0, 0.0), initial_refinement_level = 2)
290
291
J = jacobian_ad_forward(semi)
292
λ = eigvals(J)
293
@test maximum(real, λ) < 0.2
294
295
J_parabolic = jacobian_ad_forward_parabolic(semi)
296
λ_parabolic = eigvals(J_parabolic)
297
# Parabolic spectrum is real and negative
298
@test maximum(real, λ_parabolic) < eps(Float64)
299
@test maximum(imag, λ_parabolic) < 10^(-15)
300
end
301
302
@timed_testset "TreeMesh: MHD" begin
303
trixi_include(@__MODULE__,
304
joinpath(EXAMPLES_DIR, "tree_2d_dgsem",
305
"elixir_mhd_alfven_wave.jl"),
306
tspan = (0.0, 0.0), initial_refinement_level = 0)
307
@test_nowarn jacobian_ad_forward(semi)
308
end
309
310
@timed_testset "UnstructuredMesh2D: Advection" begin
311
trixi_include(@__MODULE__,
312
joinpath(EXAMPLES_DIR, "unstructured_2d_dgsem",
313
"elixir_advection_basic.jl"),
314
tspan = (0.0, 0.0))
315
316
@test_nowarn jacobian_ad_forward(semi)
317
end
318
319
@timed_testset "TreeMesh: EulerGravity" begin
320
trixi_include(@__MODULE__,
321
joinpath(EXAMPLES_DIR,
322
"paper_self_gravitating_gas_dynamics",
323
"elixir_eulergravity_convergence.jl"),
324
tspan = (0.0, 0.0), initial_refinement_level = 1)
325
J = jacobian_ad_forward(semi)
326
λ = eigvals(J)
327
@test maximum(real, λ) < 1.5
328
end
329
330
@timed_testset "StructuredMesh: Polytropic Euler equations" begin
331
trixi_include(@__MODULE__,
332
joinpath(EXAMPLES_DIR, "structured_2d_dgsem",
333
"elixir_eulerpolytropic_wave.jl"),
334
cells_per_dimension = (6, 6),
335
tspan = (0.0, 0.0))
336
337
J = jacobian_ad_forward(semi)
338
λ = eigvals(J)
339
@test maximum(real, λ) < 0.05
340
end
341
342
@timed_testset "P4estMesh: Navier-Stokes" begin
343
trixi_include(@__MODULE__,
344
joinpath(EXAMPLES_DIR, "p4est_2d_dgsem",
345
"elixir_navierstokes_viscous_shock.jl"),
346
tspan = (0.0, 0.0))
347
348
J = jacobian_ad_forward(semi)
349
λ = eigvals(J)
350
@test maximum(real, λ) < 0.05
351
352
J_parabolic = jacobian_ad_forward_parabolic(semi)
353
λ_parabolic = eigvals(J_parabolic)
354
# Parabolic spectrum is real and negative
355
@test maximum(real, λ_parabolic) < 8e-14
356
@test maximum(imag, λ_parabolic) < 8e-14
357
end
358
359
@timed_testset "T8codeMesh: Advection" begin
360
trixi_include(@__MODULE__,
361
joinpath(EXAMPLES_DIR, "t8code_2d_dgsem",
362
"elixir_advection_unstructured_flag.jl"),
363
tspan = (0.0, 0.0), initial_refinement_level = 0,
364
polydeg = 2)
365
@test_nowarn jacobian_ad_forward(semi)
366
end
367
end
368
369
@timed_testset "Test linear structure (3D)" begin
370
trixi_include(@__MODULE__,
371
joinpath(EXAMPLES_DIR, "tree_3d_dgsem",
372
"elixir_advection_extended.jl"),
373
tspan = (0.0, 0.0), initial_refinement_level = 1)
374
A, b = linear_structure(semi)
375
λ = eigvals(Matrix(A))
376
@test maximum(real, λ) < 10 * sqrt(eps(real(semi)))
377
end
378
379
@timed_testset "Test Jacobian of DG (3D)" begin
380
@timed_testset "TreeMesh: Advection" begin
381
trixi_include(@__MODULE__,
382
joinpath(EXAMPLES_DIR, "tree_3d_dgsem",
383
"elixir_advection_extended.jl"),
384
tspan = (0.0, 0.0), initial_refinement_level = 1)
385
A, _ = linear_structure(semi)
386
387
J = jacobian_ad_forward(semi)
388
@test Matrix(A) J
389
390
J = jacobian_fd(semi)
391
@test Matrix(A) J
392
end
393
394
@timed_testset "StructuredMesh: MHD" begin
395
trixi_include(@__MODULE__,
396
joinpath(EXAMPLES_DIR, "structured_3d_dgsem",
397
"elixir_mhd_alfven_wave.jl"),
398
cells_per_dimension = (2, 2, 2),
399
polydeg = 2,
400
tspan = (0.0, 0.0))
401
402
@test_nowarn jacobian_ad_forward(semi)
403
end
404
405
@timed_testset "P4estMesh: Navier-Stokes" begin
406
trixi_include(@__MODULE__,
407
joinpath(EXAMPLES_DIR, "p4est_3d_dgsem",
408
"elixir_navierstokes_convergence.jl"),
409
initial_refinement_level = 0,
410
tspan = (0.0, 0.0))
411
412
@test_nowarn jacobian_ad_forward(semi)
413
@test_nowarn jacobian_ad_forward_parabolic(semi)
414
end
415
416
@timed_testset "T8CodeMesh: Advection" begin
417
trixi_include(@__MODULE__,
418
joinpath(EXAMPLES_DIR, "t8code_3d_dgsem",
419
"elixir_advection_cubed_sphere.jl"),
420
polydeg = 2,
421
trees_per_face_dimension = 3, layers = 2,
422
tspan = (0.0, 0.0))
423
424
@test_nowarn jacobian_ad_forward(semi)
425
end
426
end
427
428
@testset "AD using ForwardDiff" begin
429
@timed_testset "Euler equations 1D" begin
430
function entropy_at_final_time(k) # k is the wave number of the initial condition
431
equations = CompressibleEulerEquations1D(1.4)
432
mesh = TreeMesh((-1.0,), (1.0,), initial_refinement_level = 3,
433
n_cells_max = 10^4, periodicity = true)
434
solver = DGSEM(3, FluxHLL(min_max_speed_naive),
435
VolumeIntegralFluxDifferencing(flux_ranocha))
436
initial_condition = (x, t, equations) -> begin
437
rho = 2 + sinpi(k * sum(x))
438
v1 = 0.1
439
p = 10.0
440
return prim2cons(SVector(rho, v1, p), equations)
441
end
442
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition,
443
solver;
444
boundary_conditions = boundary_condition_periodic,
445
uEltype = typeof(k))
446
ode = semidiscretize(semi, (0.0, 1.0))
447
summary_callback = SummaryCallback()
448
analysis_interval = 100
449
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)
450
alive_callback = AliveCallback(analysis_interval = analysis_interval)
451
callbacks = CallbackSet(summary_callback,
452
analysis_callback,
453
alive_callback)
454
sol = solve(ode, SSPRK43(), callback = callbacks)
455
return Trixi.integrate(entropy, sol.u[end], semi)
456
end
457
ForwardDiff.derivative(entropy_at_final_time, 1.0) -0.4524664696235628
458
end
459
460
@timed_testset "Linear advection 2D" begin
461
function energy_at_final_time(k) # k is the wave number of the initial condition
462
equations = LinearScalarAdvectionEquation2D(0.2, -0.7)
463
mesh = TreeMesh((-1.0, -1.0), (1.0, 1.0), initial_refinement_level = 3,
464
n_cells_max = 10^4, periodicity = true)
465
solver = DGSEM(3, flux_lax_friedrichs)
466
initial_condition = (x, t, equation) -> begin
467
x_trans = Trixi.x_trans_periodic_2d(x - equation.advection_velocity * t)
468
return SVector(sinpi(k * sum(x_trans)))
469
end
470
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition,
471
solver;
472
boundary_conditions = boundary_condition_periodic,
473
uEltype = typeof(k))
474
ode = semidiscretize(semi, (0.0, 1.0))
475
summary_callback = SummaryCallback()
476
analysis_interval = 100
477
analysis_callback = AnalysisCallback(semi, interval = analysis_interval)
478
alive_callback = AliveCallback(analysis_interval = analysis_interval)
479
stepsize_callback = StepsizeCallback(cfl = 1.6)
480
callbacks = CallbackSet(summary_callback,
481
analysis_callback,
482
alive_callback,
483
stepsize_callback)
484
sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false);
485
ode_default_options()..., adaptive = false, dt = 1.0,
486
callback = callbacks)
487
return Trixi.integrate(energy_total, sol.u[end], semi)
488
end
489
ForwardDiff.derivative(energy_at_final_time, 1.0) 1.4388628342896945e-5
490
end
491
492
@timed_testset "elixir_euler_ad.jl" begin
493
@test_trixi_include(joinpath(examples_dir(), "special_elixirs",
494
"elixir_euler_ad.jl"))
495
end
496
end
497
end
498
499
# Clean up afterwards: delete Trixi.jl output directory
500
@test_nowarn rm(outdir, recursive = true)
501
502
end #module
503
504