|
| 1 | +using OrdinaryDiffEqLowStorageRK |
| 2 | +using Trixi |
| 3 | + |
| 4 | +############################################################################### |
| 5 | +# semidiscretization of the ideal compressible Navier-Stokes equations |
| 6 | + |
| 7 | +# Fluid parameters |
| 8 | +gamma() = 1.4 |
| 9 | +prandtl_number() = 0.71 |
| 10 | + |
| 11 | +# Parameters for compressible, yet viscous set up |
| 12 | +Re() = 100 |
| 13 | +Ma() = 1.2 |
| 14 | + |
| 15 | +# Parameters that can be freely chosen |
| 16 | +v_top() = 1 |
| 17 | +rho_in() = 1 |
| 18 | +height() = 1.0 |
| 19 | + |
| 20 | +# Parameters that follow from Reynolds and Mach number + adiabatic index gamma |
| 21 | +nu() = v_top() * height() / Re() |
| 22 | + |
| 23 | +c() = v_top() / Ma() |
| 24 | +p_over_rho() = c()^2 / gamma() |
| 25 | +p_in() = rho_in() * p_over_rho() |
| 26 | +mu() = rho_in() * nu() |
| 27 | + |
| 28 | +equations = CompressibleEulerEquations2D(gamma()) |
| 29 | +equations_parabolic = CompressibleNavierStokesDiffusion2D(equations, mu = mu(), |
| 30 | + Prandtl = prandtl_number()) |
| 31 | + |
| 32 | +# Set inflow, impose known/expected velocity profile |
| 33 | +@inline function initial_condition(x, t, equations) |
| 34 | + v1 = x[2] / height() * v_top() # Linear profile from 0 to v_top |
| 35 | + v2 = 0.0 |
| 36 | + |
| 37 | + prim = SVector(rho_in(), v1, v2, p_in()) |
| 38 | + return prim2cons(prim, equations) |
| 39 | +end |
| 40 | + |
| 41 | +len() = 5 * height() # Roughly constant at this len of the channel |
| 42 | +coordinates_min = (0.0, 0.0) # minimum coordinates (min(x), min(y)) |
| 43 | +coordinates_max = (len(), height()) # maximum coordinates (max(x), max(y)) |
| 44 | + |
| 45 | +trees_per_dimension = (36, 12) |
| 46 | +mesh = P4estMesh(trees_per_dimension, polydeg = 1, |
| 47 | + coordinates_min = coordinates_min, coordinates_max = coordinates_max, |
| 48 | + periodicity = (false, false)) |
| 49 | + |
| 50 | +# Free outflow |
| 51 | +function boundary_condition_outflow(u_inner, normal_direction::AbstractVector, x, t, |
| 52 | + surface_flux_function, |
| 53 | + equations::CompressibleEulerEquations2D) |
| 54 | + # Calculate the boundary flux entirely from the internal solution state |
| 55 | + return Trixi.flux(u_inner, normal_direction, equations) |
| 56 | +end |
| 57 | + |
| 58 | +### Hyperbolic boundary conditions ### |
| 59 | +bs_hyperbolic = Dict(:x_neg => BoundaryConditionDirichlet(initial_condition), # Weakly enforced inflow BC |
| 60 | + :x_pos => boundary_condition_outflow, # Free outflow/extended domain |
| 61 | + # Top/Bottom of channel: Walls |
| 62 | + :y_neg => boundary_condition_slip_wall, |
| 63 | + :y_pos => boundary_condition_slip_wall) |
| 64 | + |
| 65 | +### Parabolic boundary conditions ### |
| 66 | + |
| 67 | +velocity_bc_top_left = NoSlip((x, t, equations) -> SVector(x[2] / height() * v_top(), 0)) |
| 68 | +# Use isothermal for inflow - adiabatic should also work |
| 69 | +heat_bc_top_left = Isothermal() do x, t, equations_parabolic |
| 70 | + Trixi.temperature(initial_condition(x, t, |
| 71 | + equations_parabolic), |
| 72 | + equations_parabolic) |
| 73 | +end |
| 74 | +bc_parabolic_top_left = BoundaryConditionNavierStokesWall(velocity_bc_top_left, |
| 75 | + heat_bc_top_left) |
| 76 | + |
| 77 | +velocity_bc_bottom = NoSlip((x, t, equations) -> SVector(0, 0)) |
| 78 | +heat_bc_bottom = Adiabatic((x, t, equations) -> 0) |
| 79 | +boundary_condition_bottom = BoundaryConditionNavierStokesWall(velocity_bc_bottom, |
| 80 | + heat_bc_bottom) |
| 81 | + |
| 82 | +# On right end: Just copy the state/gradients |
| 83 | +@inline function boundary_condition_copy(flux_inner, |
| 84 | + u_inner, |
| 85 | + normal::AbstractVector, |
| 86 | + x, t, |
| 87 | + operator_type::Trixi.Gradient, |
| 88 | + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) |
| 89 | + return u_inner |
| 90 | +end |
| 91 | +@inline function boundary_condition_copy(flux_inner, |
| 92 | + u_inner, |
| 93 | + normal::AbstractVector, |
| 94 | + x, t, |
| 95 | + operator_type::Trixi.Divergence, |
| 96 | + equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive}) |
| 97 | + return flux_inner |
| 98 | +end |
| 99 | + |
| 100 | +bcs_parabolic = Dict(:x_neg => bc_parabolic_top_left, |
| 101 | + :x_pos => boundary_condition_copy, |
| 102 | + :y_neg => boundary_condition_bottom, |
| 103 | + :y_pos => bc_parabolic_top_left) |
| 104 | + |
| 105 | +solver = DGSEM(polydeg = 3, surface_flux = flux_hll) |
| 106 | + |
| 107 | +semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic), |
| 108 | + initial_condition, solver, |
| 109 | + boundary_conditions = (bs_hyperbolic, |
| 110 | + bcs_parabolic)) |
| 111 | + |
| 112 | +############################################################################### |
| 113 | + |
| 114 | +tspan = (0, 5) |
| 115 | +ode = semidiscretize(semi, tspan) |
| 116 | + |
| 117 | +summary_callback = SummaryCallback() |
| 118 | + |
| 119 | +analysis_interval = 1000 |
| 120 | +analysis_callback = AnalysisCallback(semi, interval = analysis_interval, |
| 121 | + extra_analysis_errors = (:l2_error_primitive, |
| 122 | + :linf_error_primitive)) |
| 123 | + |
| 124 | +alive_callback = AliveCallback(analysis_interval = analysis_interval) |
| 125 | + |
| 126 | +save_solution = SaveSolutionCallback(dt = 1.0, |
| 127 | + save_initial_solution = true, |
| 128 | + save_final_solution = true, |
| 129 | + solution_variables = cons2prim) |
| 130 | + |
| 131 | +callbacks = CallbackSet(summary_callback, |
| 132 | + analysis_callback, |
| 133 | + alive_callback, |
| 134 | + save_solution) |
| 135 | + |
| 136 | +############################################################################### |
| 137 | + |
| 138 | +time_int_tol = 1e-7 |
| 139 | +sol = solve(ode, RDPK3SpFSAL49(); |
| 140 | + abstol = time_int_tol, reltol = time_int_tol, |
| 141 | + ode_default_options()..., callback = callbacks) |
0 commit comments