6: Non-periodic boundaries

Dirichlet boundary condition

First, let's look at the Dirichlet boundary condition BoundaryConditionDirichlet.

BoundaryConditionDirichlet(boundary_value_function)

In Trixi.jl, this creates a Dirichlet boundary condition where the function boundary_value_function is used to set the values at the boundary. It can be used to create a boundary condition that sets exact boundary values by passing the exact solution of the equation.

It is important to note that standard Dirichlet boundary conditions for hyperbolic PDEs do not make sense in most cases. However, we are using a special weak form of the Dirichlet boundary condition, based on the application of the numerical surface flux. The numerical surface flux takes the solution value from inside the domain and the prescribed value of the outer boundary state as arguments, and solves an approximate Riemann problem to introduce dissipation (and hence stabilization) at the boundary. Hence, the performance of the Dirichlet BC depends on the fidelity of the numerical surface flux. An easy-to read introductory reference on this topic is the paper by Mengaldo et al..

The passed boundary value function is called with the same arguments as an initial condition function, i.e.

boundary_value_function(x, t, equations)

where x specifies the spatial coordinates, t is the current time, and equations is the corresponding system of equations.

We want to give a short example for a simulation with such a Dirichlet BC.

Consider the one-dimensional linear advection equation with domain $\Omega=[0, 2]$ and a constant zero initial condition.

using OrdinaryDiffEq, Trixi

advection_velocity = 1.0
equations = LinearScalarAdvectionEquation1D(advection_velocity)

initial_condition_zero(x, t, equation::LinearScalarAdvectionEquation1D) = SVector(0.0)
initial_condition = initial_condition_zero

using Plots
plot(x -> sum(initial_condition(x, 0.0, equations)), label="initial condition", ylim=(-1.5, 1.5))
Example block output

Using an advection velocity of 1.0 and the (local) Lax-Friedrichs/Rusanov flux FluxLaxFriedrichs as a numerical surface flux, we are able to create an inflow boundary on the left and an outflow boundary on the right, as the Lax-Friedrichs flux is in this case an exact characteristics Riemann solver. We note that for more complex PDEs different strategies for inflow/outflow boundaries are necessary. To define the inflow values, we initialize a boundary_value_function.

function boundary_condition_sine_sector(x, t, equation::LinearScalarAdvectionEquation1D)
    if 1 <= t <= 3
        scalar = sin(2 * pi * sum(t - 1))
    else
        scalar = zero(t)
    end
    return SVector(scalar)
end
boundary_condition = boundary_condition_sine_sector
boundary_condition_sine_sector (generic function with 1 method)

We set the BC in negative and positive x-direction.

boundary_conditions = (x_neg=BoundaryConditionDirichlet(boundary_condition),
                       x_pos=BoundaryConditionDirichlet(boundary_condition))
(x_neg = BoundaryConditionDirichlet{typeof(Main.boundary_condition_sine_sector)}(Main.boundary_condition_sine_sector), x_pos = BoundaryConditionDirichlet{typeof(Main.boundary_condition_sine_sector)}(Main.boundary_condition_sine_sector))
solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs)

coordinates_min = (0.0,)
coordinates_max = (2.0,)
(2.0,)

For the mesh type TreeMesh the parameter periodicity must be set to false in the corresponding direction.

mesh = TreeMesh(coordinates_min, coordinates_max,
                initial_refinement_level=4,
                n_cells_max=10_000,
                periodicity=false)


semi = SemidiscretizationHyperbolic(mesh, equations,
                                    initial_condition,
                                    solver,
                                    boundary_conditions=boundary_conditions)

tspan = (0.0, 6.0)
ode = semidiscretize(semi, tspan)

analysis_callback = AnalysisCallback(semi, interval=100,)

stepsize_callback = StepsizeCallback(cfl=0.9)

callbacks = CallbackSet(analysis_callback,
                        stepsize_callback);

We define some equidistant nodes for the visualization

visnodes = range(tspan[1], tspan[2], length=300)
0.0:0.020066889632107024:6.0

and run the simulation.

sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false),
            dt=1, # solve needs some value here but it will be overwritten by the stepsize_callback
            save_everystep=false, saveat=visnodes, callback=callbacks);

using Plots
@gif for step in eachindex(sol.u)
    plot(sol.u[step], semi, ylim=(-1.5, 1.5), legend=true, label="approximation", title="time t=$(round(sol.t[step], digits=5))")
    scatter!([0.0], [sum(boundary_condition(SVector(0.0), sol.t[step], equations))], label="boundary condition")
end
Example block output

Other available example elixirs with non-trivial BC

Moreover, there are other boundary conditions in Trixi.jl. For instance, you can use the slip wall boundary condition boundary_condition_slip_wall.

Trixi.jl provides some interesting examples with different combinations of boundary conditions, e.g. using boundary_condition_slip_wall and other self-defined boundary conditions using BoundaryConditionDirichlet.

For instance, there is a 2D compressible Euler setup for a Mach 3 wind tunnel flow with a forward facing step in the elixir elixir_euler_forward_step_amr.jl discretized with a P4estMesh using adaptive mesh refinement (AMR).

Source: Video on Trixi.jl's YouTube channel Trixi Framework

A double Mach reflection problem for the 2D compressible Euler equations elixir_euler_double_mach_amr.jl exercises a special boundary conditions along the bottom of the domain that is a mixture of Dirichlet and slip wall.

Source: Video on Trixi.jl's YouTube channel Trixi Framework

A channel flow around a cylinder at Mach 3 elixir_euler_supersonic_cylinder.jl contains supersonic Mach 3 inflow at the left portion of the domain and supersonic outflow at the right portion of the domain. The top and bottom of the channel as well as the cylinder are treated as Euler slip wall boundaries.

Source: Video on Trixi.jl's YouTube channel Trixi Framework

Package versions

These results were obtained using the following versions.

using InteractiveUtils
versioninfo()

using Pkg
Pkg.status(["Trixi", "OrdinaryDiffEq", "Plots"],
           mode=PKGMODE_MANIFEST)
Julia Version 1.9.4
Commit 8e5136fa297 (2023-11-14 08:46 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 4 × AMD EPYC 7763 64-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, znver3)
  Threads: 1 on 4 virtual cores
Environment:
  JULIA_PKG_SERVER_REGISTRY_PREFERENCE = eager
Status `~/work/Trixi.jl/Trixi.jl/docs/Manifest.toml`
 [1dea7af3] OrdinaryDiffEq v6.66.0
  [91a5bcdd] Plots v1.40.4
  [a7f1ee26] Trixi v0.7.8 `~/work/Trixi.jl/Trixi.jl`
Info Packages marked with  have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated -m`

This page was generated using Literate.jl.