Equations and boundary conditions

Built-in equations

Equations are small immutable structs; the number of conserved components comes from nvariables.

EquationComponentsProblems
ConvectionEquation(v)1DGProblem
ConvectionDiffusionEquation(v, κ)1DGProblem (explicit LDG), HDGProblem, CGProblem
WaveEquation(c)3DGProblem
EulerEquations(γ)4DGProblem
PoissonEquation(κ)1HDGProblem, CGProblem

The convective velocity of ConvectionEquation/ConvectionDiffusionEquation may be a constant 2-vector or a position function x::SVector{2} -> SVector{2} (a rotating field, say) — the function form is supported by the explicit DG solvers only.

Numerical fluxes

The surface (numerical) flux is a first-class object, decoupled from the equation — any callable (eq, uL, uR, n, x, t) -> SVector:

  • RoeFlux() — Roe's approximate Riemann solver (default for Euler and the wave system),
  • LaxFriedrichs() — local Lax–Friedrichs / Rusanov (default for scalar convection; works for any equation with flux and max_abs_speed).

Every equation has a default_numerical_flux; override it per problem with DGProblem(eq, mesh; numerical_flux = LaxFriedrichs(), ...). LDG viscous penalties are likewise a policy object, LDGStabilization(c11, c11int), passed as stabilization = LDGStabilization(10.0, 0.0).

Boundary conditions

Boundary conditions are typed objects, one per boundary tag — never integer codes:

  • Dirichlet(g) — prescribed solution value: a constant, an SVector, or (x, t) -> value (for HDG/CG problems, (x, y) -> g),
  • Neumann() — homogeneous natural boundary,
  • SlipWall() — impermeable reflection wall (wave, Euler),
  • FarField(state) — free-stream state, one value per component,
  • IncomingWave() — incoming-wave forcing for the wave system.

For a DGProblem pass either a vector ordered by boundary tag, or — when the mesh carries boundary_names — a NamedTuple keyed by those names in any order:

bc = (bottom = Dirichlet(), right = Neumann(),
      top    = Dirichlet(), left  = Neumann())
prob = DGProblem(eq, mesh; bc, u0)

The conditions are carried into the kernels as a tuple, one entry per boundary tag; a face's integer tag only selects which condition applies — the physics is dispatched on the condition's type, statically per tuple slot, on CPU and GPU alike.

Defining your own physics

The physics surface is open: an equation, a numerical flux, or a boundary condition defined in your own script works in every solver path, with no package edit — see Extending TwoDG for the contract, and the Define your own equation tutorial for an executable end-to-end example with a convergence check.

Derived quantities

The Euler primitives (pressure, mach, soundspeed, density, velocity, entropy, energy_kinetic, energy_internal, energy_total) are pointwise functions (eq, u::SVector) -> Real, evaluated over a whole field with derived_field(f, eq, u) — e.g. scaplot(mesh, derived_field(mach, eq, sol.u)) — and integrated quadrature-exactly with integrate (see Callbacks and diagnostics). Any user closure with the same signature composes identically.