{ "cells": [ { "cell_type": "markdown", "source": [ "# 6: Non-periodic boundaries" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "**Note:** To improve responsiveness via caching, the notebooks are updated only once a week. They are only\n", "available for the latest stable release of Trixi.jl at the time of caching." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Dirichlet boundary condition\n", "First, let's look at the Dirichlet boundary condition `BoundaryConditionDirichlet`.\n", "```julia\n", "BoundaryConditionDirichlet(boundary_value_function)\n", "```\n", "In Trixi.jl, this creates a Dirichlet boundary condition where the function `boundary_value_function`\n", "is used to set the values at the boundary. It can be used to create a boundary condition that sets\n", "exact boundary values by passing the exact solution of the equation." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "It is important to note that standard Dirichlet boundary conditions for hyperbolic PDEs do not\n", "make sense in most cases. However, we are using a special weak form of the Dirichlet boundary\n", "condition, based on the application of the numerical surface flux. The numerical surface flux\n", "takes the solution value from inside the domain and the prescribed value of the outer boundary\n", "state as arguments, and solves an approximate Riemann problem to introduce dissipation (and\n", "hence stabilization) at the boundary. Hence, the performance of the Dirichlet BC depends on the\n", "fidelity of the numerical surface flux.\n", "An easy-to read introductory reference on this topic is the paper by\n", "[Mengaldo et al.](https://doi.org/10.2514/6.2014-2923)." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "The passed boundary value function is called with the same arguments as an initial condition\n", "function, i.e.\n", "```julia\n", "boundary_value_function(x, t, equations)\n", "```\n", "where `x` specifies the spatial coordinates, `t` is the current time, and `equations` is the\n", "corresponding system of equations." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "We want to give a short example for a simulation with such a Dirichlet BC." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Consider the one-dimensional linear advection equation with domain $\\Omega=[0, 2]$ and a constant\n", "zero initial condition." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using OrdinaryDiffEq, Trixi\n", "\n", "advection_velocity = 1.0\n", "equations = LinearScalarAdvectionEquation1D(advection_velocity)\n", "\n", "initial_condition_zero(x, t, equation::LinearScalarAdvectionEquation1D) = SVector(0.0)\n", "initial_condition = initial_condition_zero\n", "\n", "using Plots\n", "plot(x -> sum(initial_condition(x, 0.0, equations)), label=\"initial condition\", ylim=(-1.5, 1.5))" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Using an advection velocity of `1.0` and the (local) Lax-Friedrichs/Rusanov flux\n", "`FluxLaxFriedrichs` as a numerical surface flux, we are able to create an inflow boundary\n", "on the left and an outflow boundary on the right, as the Lax-Friedrichs flux is in this case an\n", "exact characteristics Riemann solver. We note that for more complex PDEs different strategies for\n", "inflow/outflow boundaries are necessary. To define the inflow values, we initialize a `boundary_value_function`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "function boundary_condition_sine_sector(x, t, equation::LinearScalarAdvectionEquation1D)\n", " if 1 <= t <= 3\n", " scalar = sin(2 * pi * sum(t - 1))\n", " else\n", " scalar = zero(t)\n", " end\n", " return SVector(scalar)\n", "end\n", "boundary_condition = boundary_condition_sine_sector" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "We set the BC in negative and positive x-direction." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "boundary_conditions = (x_neg=BoundaryConditionDirichlet(boundary_condition),\n", " x_pos=BoundaryConditionDirichlet(boundary_condition))" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "solver = DGSEM(polydeg=3, surface_flux=flux_lax_friedrichs)\n", "\n", "coordinates_min = (0.0,)\n", "coordinates_max = (2.0,)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "For the mesh type `TreeMesh` the parameter `periodicity` must be set to `false` in the\n", "corresponding direction." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "mesh = TreeMesh(coordinates_min, coordinates_max,\n", " initial_refinement_level=4,\n", " n_cells_max=10_000,\n", " periodicity=false)\n", "\n", "\n", "semi = SemidiscretizationHyperbolic(mesh, equations,\n", " initial_condition,\n", " solver,\n", " boundary_conditions=boundary_conditions)\n", "\n", "tspan = (0.0, 6.0)\n", "ode = semidiscretize(semi, tspan)\n", "\n", "analysis_callback = AnalysisCallback(semi, interval=100,)\n", "\n", "stepsize_callback = StepsizeCallback(cfl=0.9)\n", "\n", "callbacks = CallbackSet(analysis_callback,\n", " stepsize_callback);" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "We define some equidistant nodes for the visualization" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "visnodes = range(tspan[1], tspan[2], length=300)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "and run the simulation." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false),\n", " dt=1, # solve needs some value here but it will be overwritten by the stepsize_callback\n", " save_everystep=false, saveat=visnodes, callback=callbacks);\n", "\n", "using Plots\n", "@gif for step in eachindex(sol.u)\n", " plot(sol.u[step], semi, ylim=(-1.5, 1.5), legend=true, label=\"approximation\", title=\"time t=$(round(sol.t[step], digits=5))\")\n", " scatter!([0.0], [sum(boundary_condition(SVector(0.0), sol.t[step], equations))], label=\"boundary condition\")\n", "end" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "# Other available example elixirs with non-trivial BC\n", "Moreover, there are other boundary conditions in Trixi.jl. For instance, you can use the slip wall\n", "boundary condition `boundary_condition_slip_wall`." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Trixi.jl provides some interesting examples with different combinations of boundary conditions, e.g.\n", "using `boundary_condition_slip_wall` and other self-defined boundary conditions using\n", "`BoundaryConditionDirichlet`." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "For instance, there is a 2D compressible Euler setup for a Mach 3 wind tunnel flow with a forward\n", "facing step in the elixir [`elixir_euler_forward_step_amr.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/p4est_2d_dgsem/elixir_euler_forward_step_amr.jl)\n", "discretized with a `P4estMesh` using adaptive mesh refinement (AMR).\n", "\n", " \n", "
\n", "\n", "Source: [`Video`](https://www.youtube.com/watch?v=glAug1aIxio) on Trixi.jl's YouTube channel [`Trixi Framework`](https://www.youtube.com/watch?v=WElqqdMhY4A)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "A double Mach reflection problem for the 2D compressible Euler equations\n", "[`elixir_euler_double_mach_amr.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/p4est_2d_dgsem/elixir_euler_double_mach_amr.jl)\n", "exercises a special boundary conditions along the bottom of the domain that is a mixture of\n", "Dirichlet and slip wall.\n", "\n", " \n", "
\n", "\n", "Source: [`Video`](https://www.youtube.com/watch?v=WElqqdMhY4A) on Trixi.jl's YouTube channel [`Trixi Framework`](https://www.youtube.com/watch?v=WElqqdMhY4A)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "A channel flow around a cylinder at Mach 3\n", "[`elixir_euler_supersonic_cylinder.jl`](https://github.com/trixi-framework/Trixi.jl/blob/main/examples/p4est_2d_dgsem/elixir_euler_supersonic_cylinder.jl)\n", "contains supersonic Mach 3 inflow at the left portion of the domain and supersonic outflow at the\n", "right portion of the domain. The top and bottom of the channel as well as the cylinder are treated\n", "as Euler slip wall boundaries.\n", "\n", " \n", "
\n", "\n", "Source: [`Video`](https://www.youtube.com/watch?v=w0A9X38cSe4) on Trixi.jl's YouTube channel [`Trixi Framework`](https://www.youtube.com/watch?v=WElqqdMhY4A)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Package versions" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "These results were obtained using the following versions." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using InteractiveUtils\n", "versioninfo()\n", "\n", "using Pkg\n", "Pkg.status([\"Trixi\", \"OrdinaryDiffEq\", \"Plots\"],\n", " mode=PKGMODE_MANIFEST)" ], "metadata": {}, "execution_count": null } ], "nbformat_minor": 3, "metadata": { "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.10.3" }, "kernelspec": { "name": "julia-1.10", "display_name": "Julia 1.10.3", "language": "julia" } }, "nbformat": 4 }