Skip to content

alessioimprota/EulerCPP

Repository files navigation

EulerCPP

C++ CMake OpenMP Doxygen CodeFactor

EulerCPP is a standalone CFD solver for the compressible, inviscid Euler equations, written in modern C++. It supports simulations in 1D, 2D (planar or axisymmetric) and full 3D geometries on general unstructured polyhedral meshes.

At its core, EulerCPP provides several Riemann solvers for flux computation, including Rusanov, HLL, and HLLC. These can be selected via the input file, allowing flexibility depending on the problem requirements. Spatial accuracy is achieved through MUSCL reconstruction with slope limiters. Time integration can be performed either with an explicit multi-stage scheme, with an implicit scheme for steady-state simulations or with an implicit unsteady scheme with dual time-stepping.

Results are exported in the standard VTK format (ASCII or binary) or CSV format, making them easy to visualize with ParaView or similar post-processing tools. Parallelism is supported through OpenMP, enabling efficient use of multi-core CPUs.

Examples

This section presents a set of canonical test cases demonstrating EulerCPP capabilities in 1D, 2D, axisymmetric and 3D flows.

1D Sod shock tube problem

The 1D Sod shock tube is a standard Riemann problem featuring a discontinuity in density and pressure, generating a shock, contact discontinuity, and expansion fan. It is widely used to validate shock-capturing schemes.

The figures below show results at time 0.2 seconds on a 1000 elements mesh using the HLLC Riemann solver, second-order MUSCL reconstruction with Venkatakrishnan slope limiter and a 5-stage explicit time integration scheme. Input file and mesh files used for this problem are available in the examples folder.

1D Sod shock tube

2D Explosion

This classical benchmark consists of a strong explosion initialized at the center of a square domain. The large pressure ratio between the central region and the surroundings drives the formation of shocks and rarefactions waves that interact in a highly nonlinear way.

The animations below illustrate the Mach number and pressure evolution over time. Results were obtained using the HLLC Riemann solver and second-order MUSCL reconstruction with Venkatakrishnan slope limiter and a 5-stage explicit time integration scheme. Input file and mesh files used for this simulation are available in the examples folder.

2D Explosion

2D Supersonic cylinder

The 2D supersonic cylinder case consists of uniform freestream flow at Mach 3 impinging on a circular cylinder. A detached bow shock forms upstream of the cylinder, while a complex subsonic recirculation region develops in the wake. This benchmark is widely used to validate shock-capturing capability in two dimensions, as well as the treatment of slip-wall boundaries and far-field boundary conditions.

The animations below illustrate the development of the bow shock and the pressure field. Results were obtained using the HLLC Riemann solver and second-order MUSCL reconstruction with Venkatakrishnan slope limiter. Input file and mesh file used for this simulation are available in the examples folder.

2D Supersonic cylinder

NACA0012 Airfoil

The NACA0012 airfoil is a classical benchmark in computational aerodynamics, widely used for the validation of compressible flow solvers. In this case, the airfoil is tested at Mach 0.5 and an angle of attack of 2 degrees.

The figure below compares the Mach number distribution around the airfoil obtained with EulerCPP (left) and Siemens Simcenter STAR-CCM+ (right). Results were obtained using the HLLC Riemann solver, second-order MUSCL reconstruction with Venkatakrishnan slope limiter and an explicit time integration scheme with local time-stepping. Input file and mesh file used for this simulation are available in the examples folder.

NACA0012 Airfoil

Axisymmetric rocket nozzle

This test case simulates compressible flow through a convergent–divergent nozzle in an axisymmetric configuration. The setup includes a stagnation chamber, throat, and expanding section, producing supersonic exhaust with a characteristic structure in the jet plume. The wake and shock interactions downstream are well-suited to demonstrate the solver’s axisymmetric capabilities.

The animation below shows the temperature field during the simulation, highlighting the supersonic expansion and shock patterns in the exhaust jet. Results were obtained using the HLLC Riemann solver and second-order MUSCL reconstruction with the Venkatakrishnan slope limiter. The input file and mesh used for this simulation are available in the examples folder.

Axisymmetric rocket nozzle

3D Intermediate eXperimental Vehicle

This example simulates the final re-entry phase of the ESA Intermediate eXperimental Vehicle (IXV), a lifting body designed to demonstrate key re-entry technologies. The flow conditions correspond to Mach 2 at 45° angle of attack, producing a highly asymmetric shock system.

The case highlights the solver’s capability to handle large-scale 3D unstructured meshes (over 5 million elements) and to capture shocks around complex geometries.

Results were obtained using the HLLC Riemann solver and second-order MUSCL reconstruction with the Venkatakrishnan slope limiter.

IXV

Installation

Using prebuilt packages

Prebuilt packages are available on the Releases page:

  • macOS: eulercpp-<version>-macos.pkg
  • Windows: eulercpp-<version>-win.exe
  • Linux (Debian/Ubuntu): eulercpp-<version>-linux.deb
  • Linux (Fedora/RHEL/openSUSE): eulercpp-<version>-linux.rpm

MacOS

On macOS, just double-click the .pkg file and follow the procedure.
After installation, the software will be available system-wide in your PATH.

Windows

Run the .exe installer and follow the installation steps.
During installation you can enable adding EulerCPP to your PATH.
If not, add the following manually:

C:\Program Files\eulercpp\bin

Linux

# Debian / Ubuntu
sudo apt install ./eulercpp-<version>-linux.deb

# Fedora/RHEL/openSUSE
sudo rpm -i eulercpp-<version>-linux.rpm

After installation, the software will be available system-wide in your PATH.

Building from source

Requirements for building from source

  • CMake (≥ 3.10)
  • C++17 or newer compiler
  • OpenMP (for parallelism)
  • Ninja (recommended for Windows)

Requirements for generating installers with CPack

  • Windows: NSIS
  • macOS: none
  • Debian/Ubuntu: dpkg-dev, fakeroot
  • Fedora/RHEL/openSUSE: rpm-build

Clone the repository:

git clone https://github.com/alessioimprota/EulerCPP.git

cd EulerCPP

Use helper scripts:

# MacOS / Linux
./build.sh

# Windows (PowerShell)
.\build.ps1

or build manually:

# MacOS / Linux
mkdir build
cd build
cmake ..
cmake --build .

# Windows
mkdir build
cd build
cmake -G "Ninja" ..
cmake --build .

This creates the eulercpp executable in the bin/ directory, together with all tool binaries.

Additionally, CPack can generate installable packages in the build/ directory:

cpack

This will produce:

  • .pkg on macOS
  • .exe on Windows
  • .deb / .rpm on Linux

These packages can then be installed system-wide using the methods above.

Uninstallation

MacOS

Applications installed via .pkg can be removed using a third-party uninstaller tool, or manually by deleting the installed files (typically in /usr/local/bin/ and /usr/local/include/).

Windows

Use Add/Remove Programs in the Control Panel.

Linux

# Debian/Ubuntu
sudo apt remove eulercpp

# Fedora/RHEL/OpenSUSE
sudo rpm -e eulercpp

Usage

Run a simulation by providing an input file:

eulercpp input.inp

Input file format

# EulerCPP input file example

# Notes:
# - Any line starting with `#` is a comment.
# - Lines with an `=` sign are parsed as key = value pairs.

# Logger settings
# Controls verbosity and logging output.
# verbosity: (0 = silent, ..., 5 = debug)
# log_file: optional path to log file
# rhs_file: optional file for residual history
#           (if provided, residuals are written only there)
verbosity=4
log_file=output.log

# Physics settings
# dimension: problem dimensionality
# 0 = 1D, 1 = 2D (XY), 2 = Axisymmetric (XY, X-axis), 3 = 3D
dimension=1

# Mesh settings
# mesh_file: path to mesh file in gmsh 2.2 format (.msh).
# min_volume: minimum allowed element volume.
mesh_file=mesh.msh
min_volume=1.0e-20

# Fluid settings
# R: specific gas constant [J/kgK]
# gamma: heat capacity ratio
R=287.0
gamma=1.4

# Solver settings
# time_integration:
#    0 = explicit, 1 = implicit steady, 2 = implicit unsteady
# dual_time_scheme (for implicit unsteady):
#    0 = BDF, 1 = BDF2, 2 = BDF2Opt4, 3 = BDF2Opt5
# inner_iterations: number of inner iterations (for implicit unsteady)
# timestep: timestep size (for implicit unsteady)
# local_timestep: 0 = disabled, 1 = enabled
# time_stages: number of time integration stages
# a: coefficients for multi-stage time integration
# CFL: CFL number
# maxtime: maximum physical simulation time
# maxiter: maximum number of iterations
# reconstruction: 0 = 1st order, 1 = 2nd order (MUSCL)
# limiter: slope limiter
#    0 = minmod, 1 = superbee, 2 = van Leer,
#    3 = Venkatakrishnan, 4 = modified Venkatakrishnan
# riemann: riemann solver
#    0 = Rusanov, 1 = HLL, 2 = HLLC
time_integration=0
dual_time_scheme=1
inner_iterations=5
timestep=1.0e-4
local_timestep=0
time_stages=5
a=0.25,0.1666667,0.375,0.5,1.0
CFL=0.8
maxtime=0.2
maxiter=10000
reconstruction=1
limiter=3
riemann=2

# Linear solver settings
# solver_maxiter: linear solver maximum iterations
# solver_tol: linear solver relative tolerance
# solver_verbose: if 1 enables solver verbose mode
# solver_alpha: implicit alpha coefficient
# solver_under_relaxation: explicit under_relaxation
# solver_target: linear solver target iterations
# second_order_jacobians: if 1 use 2nd-order Jacobians
# cfl_max: maximum CFL number
# cfl_min: minimum CFL number
# cfl_ramp: CFL ramp coefficient
solver_maxiter=5
solver_tol=0.001
solver_verbose=0
solver_alpha=1.0
solver_under_relaxation=1.0
solver_target=3
second_order_jacobians=0
cfl_max=1.0e5
cfl_min=0.1
cfl_ramp=1.1

# Output settings
# output_format: 0 = VTK binary, 1 = VTK ASCII, 2 = CSV
# output_delay: iterations between solution dumps
# prints_delay: iterations between printing residuals
# prints_info_delay: iterations between printing header
# restart_delay: iterations between restart file saves
# restart_format: 0 = binary, 1 = ASCII
# output_folder: directory for output files
# output_name: prefix for output/restart files
output_format=0
output_delay=1000
prints_delay=1
prints_info_delay=20
restart_delay=500
restart_format=0
output_folder=output
output_name=output

# Probes
# n_probes: number of probes
# probe_X=x,y,z: probe X location
n_probes=1
probe_1=0.0,0.0,0.0

# Reports
# n_reports: number of reports
# report_X=Y: assign Y boundary to X report
# report_X_cg=x,y,z: report center of gravity
n_reports=1
report_1=1
report_1_cg=0.0,0.0,0.0

# Initial conditions
# - restart: 0 = start from scratch, 1 = start from restart file
# - restart_file: path to restart file (if restart=1)
# - initial_variables:
#    0 = specify T_0
#    1 = specify rho_0
# - additional_blocks: number of override regions (boxes)
#
# Default block defines the background state.
# Each block_b overrides it in a defined region:
#   p_b, rho_b (or T_b), u_b, v_b, w_b
#   either using XYZ boxes:
#   xmin_b, xmax_b, ymin_b, ymax_b, zmin_b, zmax_b
#   or spheres:
#   center_b=0.0,0.0,0.0 ; radius_b=1.0
restart=0
restart_file=output/output.restart
initial_variables=1
additional_blocks=1

# Default block
p_0=1.0
rho_0=1.0
u_0=0.0
v_0=0.0
w_0=0.0

# Block 1
p_1=0.1
rho_1=0.125
u_1=0.0
v_1=0.0
w_1=0.0
xmin_1=0.5

# Boundary conditions
# n_boundaries: number of boundary conditions
# For each boundary:
#   bc_X: boundary type (integer code)
#       - 0 = Supersonic inflow
#       - 1 = Supersonic outflow
#       - 2 = Stagnation inlet
#       - 3 = Subsonic inflow
#       - 4 = Pressure outlet
#       - 5 = Wall (same as symmetry)
#       - 6 = Symmetry condition
#       - 7 = Slip wall (same as symmetry)
#       - 8 = Moving wall (same as symmetry)
#       - 9 = Axis condition
#   bc_X_var_Y: boundary variables (depend on type)
#       Supersonic inflow: [Mach, p, T, alpha, phi]
#           (alpha and phi are flow direction angles)
#       Stagnation inlet: [Htot, Ptot, Psup, alpha, phi]
#       Subsonic inflow: [T, u, v, w]
#       Pressure outlet: [p]
#       Others: []
#   bc_X_direction=x,y,z: flow direction
#       if flow direction is specified, angles are ignored
#   bc_X_xmin, xmax, ymin, ymax, zmin, zmax: bounding box
#   bc_X_center, bc_X_radius: bounding sphere
# Boundary conditions can also be assigned directly from mesh file using tags.
n_boundaries=1
bc_1=6

# Example of a supersonic inlet from the left of the domain:
# bc_1=0 (Supersonic inflow)
# bc_1_var_1 = 3.0 (Mach number)
# bc_1_var_2 = 101325.0 (Pressure)
# bc_1_var_3 = 300.0 (Temperature)
# bc_1_var_4 = 0.0 (Alpha angle)
# bc_1_var_5 = 0.0 (Phi angle)
# bc_1_direction = 1.0,0.0,0.0 (Flow direction)
# If flow direction is specified, flow angles are ignored
# bc_1_xmax = -2.0 (X-bounded)

Tools

EulerCPP also provides additional tools for working with meshes and simulations.

maprestart

maprestart is a utility for transferring solution fields from an existing simulation to a new mesh.
It finds, for each element in the new mesh, the closest element in the old mesh using a KD-tree nearest-neighbor search, and maps the solution fields accordingly.

Example of usage:

maprestart mesh.msh restart_file.restart new_mesh.msh new_restart_file.restart

This tool is useful for continuing simulations after mesh refinement, coarsening, or other mesh modifications.

API Reference

Full API reference generated with Doxygen, with the help of ChatGPT.

See the provided Doxyfile and build with:

doxygen docs/Doxyfile

Changelog

See CHANGELOG.md

License

See LICENSE.txt