Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/examples/p4est_2d_dgsem/elixir_euler_subsonic_cylinder.jl
2055 views
1
using OrdinaryDiffEqLowStorageRK
2
using Trixi
3
4
###############################################################################
5
# semidiscretization of the compressible Euler equations
6
7
equations = CompressibleEulerEquations2D(1.4)
8
9
@inline function initial_condition_mach038_flow(x, t,
10
equations::CompressibleEulerEquations2D)
11
# set the freestream flow parameters
12
rho_freestream = 1.4
13
v1 = 0.38
14
v2 = 0.0
15
p_freestream = 1.0
16
17
prim = SVector(rho_freestream, v1, v2, p_freestream)
18
return prim2cons(prim, equations)
19
end
20
21
initial_condition = initial_condition_mach038_flow
22
23
volume_flux = flux_ranocha_turbo # FluxRotated(flux_chandrashekar) can also be used
24
# Up to version 0.13.0, `max_abs_speed_naive` was used as the default wave speed estimate of
25
# `const flux_lax_friedrichs = FluxLaxFriedrichs(), i.e., `FluxLaxFriedrichs(max_abs_speed = max_abs_speed_naive)`.
26
# In the `StepsizeCallback`, though, the less diffusive `max_abs_speeds` is employed which is consistent with `max_abs_speed`.
27
# Thus, we exchanged in PR#2458 the default wave speed used in the LLF flux to `max_abs_speed`.
28
# To ensure that every example still runs we specify explicitly `FluxLaxFriedrichs(max_abs_speed_naive)`.
29
# We remark, however, that the now default `max_abs_speed` is in general recommended due to compliance with the
30
# `StepsizeCallback` (CFL-Condition) and less diffusion.
31
surface_flux = FluxLaxFriedrichs(max_abs_speed_naive)
32
33
polydeg = 3
34
solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux,
35
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))
36
37
function mapping2cylinder(xi, eta)
38
xi_, eta_ = 0.5 * (xi + 1), 0.5 * (eta + 1.0) # Map from [-1,1] to [0,1] for simplicity
39
40
R2 = 50.0 # Bigger circle
41
R1 = 0.5 # Smaller circle
42
43
# Ensure an isotropic mesh by using elements with smaller radial length near the inner circle
44
45
r = R1 * exp(xi_ * log(R2 / R1))
46
theta = 2.0 * pi * eta_
47
48
x = r * cos(theta)
49
y = r * sin(theta)
50
return (x, y)
51
end
52
53
cells_per_dimension = (64, 64)
54
# xi = -1 maps to the inner circle and xi = +1 maps to the outer circle and we can specify boundary
55
# conditions there. However, the image of eta = -1, +1 coincides at the line y = 0. There is no
56
# physical boundary there so we specify `periodicity = true` there and the solver treats the
57
# element across eta = -1, +1 as neighbours which is what we want
58
mesh = P4estMesh(cells_per_dimension, mapping = mapping2cylinder, polydeg = polydeg,
59
periodicity = (false, true))
60
61
# The boundary condition on the outer cylinder is constant but subsonic, so we cannot compute the
62
# boundary flux from the external information alone. Thus, we use the numerical flux to distinguish
63
# between inflow and outflow characteristics
64
@inline function boundary_condition_subsonic_constant(u_inner,
65
normal_direction::AbstractVector, x,
66
t,
67
surface_flux_function,
68
equations::CompressibleEulerEquations2D)
69
u_boundary = initial_condition_mach038_flow(x, t, equations)
70
71
return surface_flux_function(u_inner, u_boundary, normal_direction, equations)
72
end
73
74
boundary_conditions = Dict(:x_neg => boundary_condition_slip_wall,
75
:x_pos => boundary_condition_subsonic_constant)
76
77
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
78
boundary_conditions = boundary_conditions)
79
80
###############################################################################
81
# ODE solvers
82
83
# Run for a long time to reach a steady state
84
tspan = (0.0, 100.0)
85
ode = semidiscretize(semi, tspan)
86
87
# Callbacks
88
89
summary_callback = SummaryCallback()
90
91
analysis_interval = 2000
92
93
aoa = 0.0
94
rho_inf = 1.4
95
u_inf = 0.38
96
l_inf = 1.0 # Diameter of circle
97
98
force_boundary_symbol = (:x_neg,)
99
drag_coefficient = AnalysisSurfaceIntegral(force_boundary_symbol,
100
DragCoefficientPressure2D(aoa, rho_inf, u_inf,
101
l_inf))
102
103
lift_coefficient = AnalysisSurfaceIntegral(force_boundary_symbol,
104
LiftCoefficientPressure2D(aoa, rho_inf, u_inf,
105
l_inf))
106
107
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
108
output_directory = "out",
109
save_analysis = true,
110
analysis_integrals = (drag_coefficient,
111
lift_coefficient))
112
113
alive_callback = AliveCallback(analysis_interval = analysis_interval)
114
115
save_solution = SaveSolutionCallback(interval = 500,
116
save_initial_solution = true,
117
save_final_solution = true,
118
solution_variables = cons2prim)
119
120
stepsize_callback = StepsizeCallback(cfl = 2.0)
121
122
callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution,
123
stepsize_callback)
124
125
###############################################################################
126
# run the simulation
127
sol = solve(ode,
128
CarpenterKennedy2N54(williamson_condition = false;
129
thread = Trixi.True());
130
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
131
ode_default_options()..., callback = callbacks);
132
133