1.1: First steps in Trixi.jl: Getting started
Trixi.jl is a numerical simulation framework for conservation laws and is written in the Julia programming language. This tutorial is intended for beginners in Julia and Trixi.jl. After reading it, you will know how to install Julia and Trixi.jl on your computer, and you will be able to download setup files from our GitHub repository, modify them, and run simulations.
The contents of this tutorial:
- Julia installation
- Trixi.jl installation
- Running a simulation
- Getting an existing setup file
- Modifying an existing setup
Julia installation
Trixi.jl is compatible with the latest stable release of Julia. Additional details regarding Julia support can be found in the README.md
file. The current default Julia installation is managed through juliaup
. You may follow our concise installation guidelines for Windows, Linux, and MacOS provided below. In the event of any issues during the installation process, please consult the official Julia installation instruction.
Windows
- Open a terminal by pressing
Win+r
and enteringcmd
in the opened window. - To install Julia, execute the following command in the terminal:
winget install julia -s msstore
- Verify the successful installation of Julia by executing the following command in the terminal:
To exit Julia, executejulia
exit()
or pressCtrl+d
.
Linux and MacOS
- To install Julia, run the following command in a terminal:
Follow the instructions displayed in the terminal during the installation process.curl -fsSL https://install.julialang.org | sh
- If an error occurs during the execution of the previous command, you may need to install
curl
. On Ubuntu-type systems, you can use the following command:
After installingsudo apt install curl
curl
, repeat the first step once more to proceed with Julia installation. - Verify the successful installation of Julia by executing the following command in the terminal:
To exit Julia, executejulia
exit()
or pressCtrl+d
.
Trixi.jl installation
Trixi.jl and its related tools are registered Julia packages, thus their installation happens inside Julia. For a smooth workflow experience with Trixi.jl, you need to install Trixi.jl, OrdinaryDiffEq.jl, and Plots.jl.
- Open a terminal and start Julia.
- Execute following commands:
import Pkg Pkg.add(["OrdinaryDiffEq", "Plots", "Trixi"])
Now you have installed all these packages. OrdinaryDiffEq.jl provides time integration schemes used by Trixi.jl and Plots.jl can be used to directly visualize Trixi.jl results from the Julia REPL.
Usage
Running a simulation
To get you started, Trixi.jl has a large set of example setups, that can be taken as a basis for your future investigations. In Trixi.jl, we call these setup files "elixirs", since they contain Julia code that takes parts of Trixi.jl and combines them into something new.
Any of the examples can be executed using the trixi_include
function. trixi_include(...)
expects a single string argument with a path to a file containing Julia code. For convenience, the examples_dir
function returns a path to the examples
folder, which has been locally downloaded while installing Trixi.jl. joinpath(...)
can be used to join path components into a full path.
Let's execute a short two-dimensional problem setup. It approximates the solution of the compressible Euler equations in 2D for an ideal gas (CompressibleEulerEquations2D
) with a weak blast wave as the initial condition.
Start Julia in a terminal and execute the following code:
using Trixi, OrdinaryDiffEq
trixi_include(joinpath(examples_dir(), "tree_2d_dgsem", "elixir_euler_ec.jl"))
[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.
████████╗██████╗ ██╗██╗ ██╗██╗
╚══██╔══╝██╔══██╗██║╚██╗██╔╝██║
██║ ██████╔╝██║ ╚███╔╝ ██║
██║ ██╔══██╗██║ ██╔██╗ ██║
██║ ██║ ██║██║██╔╝ ██╗██║
╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ SemidiscretizationHyperbolic │
│ ════════════════════════════ │
│ #spatial dimensions: ………………………… 2 │
│ mesh: ………………………………………………………………… TreeMesh{2, Trixi.SerialTree{2}} with length 1365 │
│ equations: …………………………………………………… CompressibleEulerEquations2D │
│ initial condition: ……………………………… initial_condition_weak_blast_wave │
│ boundary conditions: ………………………… Trixi.BoundaryConditionPeriodic │
│ source terms: …………………………………………… nothing │
│ solver: …………………………………………………………… DG │
│ total #DOFs per field: …………………… 16384 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TreeMesh{2, Trixi.SerialTree{2}} │
│ ════════════════════════════════ │
│ center: …………………………………………………………… [0.0, 0.0] │
│ length: …………………………………………………………… 4.0 │
│ periodicity: ……………………………………………… (true, true) │
│ current #cells: ……………………………………… 1365 │
│ #leaf-cells: ……………………………………………… 1024 │
│ maximum #cells: ……………………………………… 10000 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CompressibleEulerEquations2D │
│ ════════════════════════════ │
│ #variables: ………………………………………………… 4 │
│ │ variable 1: …………………………………………… rho │
│ │ variable 2: …………………………………………… rho_v1 │
│ │ variable 3: …………………………………………… rho_v2 │
│ │ variable 4: …………………………………………… rho_e │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ DG{Float64} │
│ ═══════════ │
│ basis: ……………………………………………………………… LobattoLegendreBasis{Float64}(polydeg=3) │
│ mortar: …………………………………………………………… LobattoLegendreMortarL2{Float64}(polydeg=3) │
│ surface integral: ………………………………… SurfaceIntegralWeakForm │
│ │ surface flux: ……………………………………… flux_ranocha │
│ volume integral: …………………………………… VolumeIntegralFluxDifferencing │
│ │ volume flux: ………………………………………… flux_ranocha │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ AnalysisCallback │
│ ════════════════ │
│ interval: ……………………………………………………… 100 │
│ analyzer: ……………………………………………………… LobattoLegendreAnalyzer{Float64}(polydeg=6) │
│ │ error 1: …………………………………………………… l2_error │
│ │ error 2: …………………………………………………… linf_error │
│ │ integral 1: …………………………………………… entropy_timederivative │
│ save analysis to file: …………………… no │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ AliveCallback │
│ ═════════════ │
│ interval: ……………………………………………………… 10 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ SaveSolutionCallback │
│ ════════════════════ │
│ interval: ……………………………………………………… 100 │
│ solution variables: …………………………… cons2prim │
│ save initial solution: …………………… yes │
│ save final solution: ………………………… yes │
│ output directory: ………………………………… /home/runner/work/Trixi.jl/Trixi…build/tutorials/first_steps/out │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ StepsizeCallback │
│ ════════════════ │
│ CFL number: ………………………………………………… 1.0 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Time integration │
│ ════════════════ │
│ Start time: ………………………………………………… 0.0 │
│ Final time: ………………………………………………… 0.4 │
│ time integrator: …………………………………… CarpenterKennedy2N54 │
│ adaptive: ……………………………………………………… false │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Environment information │
│ ═══════════════════════ │
│ #threads: ……………………………………………………… 1 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────────────────────────
Simulation running 'CompressibleEulerEquations2D' with DGSEM(polydeg=3)
────────────────────────────────────────────────────────────────────────────────────────────────────
#timesteps: 0 run time: 8.92000000e-07 s
Δt: 1.00000000e+00 └── GC time: 0.00000000e+00 s (0.000%)
sim. time: 0.00000000e+00 (0.000%) time/DOF/rhs!: NaN s
PID: Inf s
#DOFs per field: 16384 alloc'd memory: 3814.566 MiB
#elements: 1024
Variable: rho rho_v1 rho_v2 rho_e
L2 error: 6.25621384e-03 5.88786362e-03 5.81457821e-03 2.34267393e-02
Linf error: 1.06470791e-01 2.46283676e-01 1.37585923e-01 3.98685775e-01
∑∂S/∂U ⋅ Uₜ : 2.63255193e-19
────────────────────────────────────────────────────────────────────────────────────────────────────
#timesteps: 10 │ Δt: 1.0797e-02 │ sim. time: 1.0745e-01 (26.862%) │ run time: 8.1798e-02 s
#timesteps: 20 │ Δt: 1.1033e-02 │ sim. time: 2.1692e-01 (54.229%) │ run time: 1.6182e-01 s
#timesteps: 30 │ Δt: 1.1481e-02 │ sim. time: 3.3075e-01 (82.688%) │ run time: 2.4370e-01 s
────────────────────────────────────────────────────────────────────────────────────────────────────
Simulation running 'CompressibleEulerEquations2D' with DGSEM(polydeg=3)
────────────────────────────────────────────────────────────────────────────────────────────────────
#timesteps: 37 run time: 3.05788205e-01 s
Δt: 4.74704430e-04 └── GC time: 0.00000000e+00 s (0.000%)
sim. time: 4.00000000e-01 (100.000%) time/DOF/rhs!: 9.19024694e-08 s
PID: 9.89450070e-08 s
#DOFs per field: 16384 alloc'd memory: 3816.206 MiB
#elements: 1024
Variable: rho rho_v1 rho_v2 rho_e
L2 error: 6.17517156e-02 5.01822362e-02 5.01898945e-02 2.25871560e-01
Linf error: 2.93475829e-01 3.10812492e-01 3.10738039e-01 1.05403580e+00
∑∂S/∂U ⋅ Uₜ : -2.09794309e-18
────────────────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────────────────────────
Trixi.jl simulation finished. Final time: 0.4 Time steps: 37 (accepted), 37 (total)
────────────────────────────────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────────
Trixi.jl Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 312ms / 94.9% 3.69MiB / 85.8%
Section ncalls time %tot avg alloc %tot avg
────────────────────────────────────────────────────────────────────────────────
rhs! 186 280ms 94.6% 1.51ms 9.33KiB 0.3% 51.4B
volume integral 186 201ms 67.8% 1.08ms 0.00B 0.0% 0.00B
interface flux 186 41.9ms 14.2% 225μs 0.00B 0.0% 0.00B
surface integral 186 17.4ms 5.9% 93.6μs 0.00B 0.0% 0.00B
prolong2interfaces 186 15.8ms 5.3% 84.8μs 0.00B 0.0% 0.00B
Jacobian 186 2.08ms 0.7% 11.2μs 0.00B 0.0% 0.00B
reset ∂u/∂t 186 1.88ms 0.6% 10.1μs 0.00B 0.0% 0.00B
~rhs!~ 186 306μs 0.1% 1.65μs 9.33KiB 0.3% 51.4B
prolong2boundaries 186 12.1μs 0.0% 64.8ns 0.00B 0.0% 0.00B
prolong2mortars 186 11.6μs 0.0% 62.4ns 0.00B 0.0% 0.00B
mortar flux 186 8.99μs 0.0% 48.4ns 0.00B 0.0% 0.00B
boundary flux 186 6.25μs 0.0% 33.6ns 0.00B 0.0% 0.00B
source terms 186 5.39μs 0.0% 29.0ns 0.00B 0.0% 0.00B
analyze solution 2 8.43ms 2.8% 4.22ms 54.6KiB 1.7% 27.3KiB
I/O 3 3.98ms 1.3% 1.33ms 3.10MiB 98.0% 1.03MiB
save solution 2 3.12ms 1.1% 1.56ms 3.02MiB 95.4% 1.51MiB
~I/O~ 3 855μs 0.3% 285μs 84.9KiB 2.6% 28.3KiB
get element vari... 2 350ns 0.0% 175ns 0.00B 0.0% 0.00B
save mesh 2 150ns 0.0% 75.0ns 0.00B 0.0% 0.00B
get node variables 2 140ns 0.0% 70.0ns 0.00B 0.0% 0.00B
calculate dt 38 3.64ms 1.2% 95.8μs 0.00B 0.0% 0.00B
────────────────────────────────────────────────────────────────────────────────
To analyze the result of the computation, we can use the Plots.jl package and the function plot(...)
, which creates a graphical representation of the solution. sol
is a variable defined in the executed example and it contains the solution at the final moment of the simulation.
using Plots
plot(sol)
To obtain a list of all Trixi.jl elixirs execute get_examples
. It returns the paths to all example setups.
get_examples()
391-element Vector{String}:
"/home/runner/work/Trixi.jl/Trix" ⋯ 23 bytes ⋯ "d/elixir_advection_gauss_sbp.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 24 bytes ⋯ "/elixir_euler_fdsbp_periodic.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 19 bytes ⋯ "ti_1d/elixir_euler_flux_diff.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 18 bytes ⋯ "lti_1d/elixir_euler_quasi_1d.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 26 bytes ⋯ "lixir_shallow_water_quasi_1d.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 23 bytes ⋯ "d/elixir_advection_diffusion.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 35 bytes ⋯ "ection_diffusion_nonperiodic.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 32 bytes ⋯ "advection_diffusion_periodic.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 18 bytes ⋯ "lti_2d/elixir_euler_bilinear.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 29 bytes ⋯ "ir_euler_brown_minion_vortex.jl"
⋮
"/home/runner/work/Trixi.jl/Trix" ⋯ 45 bytes ⋯ "allowwater_ec_shockcapturing.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 40 bytes ⋯ "ir_shallowwater_source_terms.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 50 bytes ⋯ "water_wall_bc_shockcapturing.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 41 bytes ⋯ "r_shallowwater_well_balanced.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 30 bytes ⋯ "fdsbp/elixir_advection_basic.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 32 bytes ⋯ "sbp/elixir_euler_free_stream.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 39 bytes ⋯ "xir_euler_free_stream_upwind.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 33 bytes ⋯ "bp/elixir_euler_source_terms.jl"
"/home/runner/work/Trixi.jl/Trix" ⋯ 40 bytes ⋯ "ir_euler_source_terms_upwind.jl"
Editing an existing elixir is the best way to start your first own investigation using Trixi.jl.
Getting an existing setup file
To edit an existing elixir, you first have to find a suitable one and then copy it to a local folder. Let's have a look at how to download the elixir_euler_ec.jl
elixir used in the previous section from the Trixi.jl GitHub repository.
- All examples are located inside the
examples
folder. - Navigate to the file
elixir_euler_ec.jl
. - Right-click the
Raw
button on the right side of the webpage and chooseSave as...
(orSave Link As...
). - Choose a folder and save the file.
Modifying an existing setup
As an example, we will change the initial condition for calculations that occur in elixir_euler_ec.jl
. In this example we consider the compressible Euler equations in two spatial dimensions,
\[\frac{\partial}{\partial t} \begin{pmatrix} \rho \\ \rho v_1 \\ \rho v_2 \\ \rho e \end{pmatrix} + \frac{\partial}{\partial x} \begin{pmatrix} \rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ (\rho e + p) v_1 \end{pmatrix} + \frac{\partial}{\partial y} \begin{pmatrix} \rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ (\rho e + p) v_2 \end{pmatrix} = \begin{pmatrix} 0 \\ 0 \\ 0 \\ 0 \end{pmatrix},\]
for an ideal gas with the specific heat ratio $\gamma$. Here, $\rho$ is the density, $v_1$ and $v_2$ are the velocities, $e$ is the specific total energy, and
\[p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2 + v_2^2) \right)\]
is the pressure. Initial conditions consist of initial values for $\rho$, $\rho v_1$, $\rho v_2$ and $\rho e$. One of the common initial conditions for the compressible Euler equations is a simple density wave. Let's implement it.
- Open the downloaded file
elixir_euler_ec.jl
with a text editor. - Go to the line with the following code:
Here,initial_condition = initial_condition_weak_blast_wave
initial_condition_weak_blast_wave
is used as the initial condition. - Comment out the line using the
#
symbol:# initial_condition = initial_condition_weak_blast_wave
- Now you can create your own initial conditions. Add the following code after the commented line:
function initial_condition_density_waves(x, t, equations::CompressibleEulerEquations2D)
v1 = 0.1 # velocity along x-axis
v2 = 0.2 # velocity along y-axis
rho = 1.0 + 0.98 * sinpi(sum(x) - t * (v1 + v2)) # density wave profile
p = 20 # pressure
rho_e = p / (equations.gamma - 1) + 1/2 * rho * (v1^2 + v2^2)
return SVector(rho, rho*v1, rho*v2, rho_e)
end
initial_condition = initial_condition_density_waves
initial_condition_density_waves (generic function with 1 method)
- Execute the following code one more time, but instead of
path/to/file
paste the path to theelixir_euler_ec.jl
file that you just edited.using Trixi trixi_include(path/to/file) using Plots plot(sol)
Then you will obtain a new solution from running the simulation with a different initial condition.
To get exactly the same picture execute the following.
pd = PlotData2D(sol)
p1 = plot(pd["rho"])
p2 = plot(pd["v1"], clim=(0.05, 0.15))
p3 = plot(pd["v2"], clim=(0.15, 0.25))
p4 = plot(pd["p"], clim=(10, 30))
plot(p1, p2, p3, p4)
Feel free to make further changes to the initial condition to observe different solutions.
Now you are able to download, modify and execute simulation setups for Trixi.jl. To explore further details on setting up a new simulation with Trixi.jl, refer to the second part of the introduction titled Create first setup.
This page was generated using Literate.jl.