Skip to content

Forward-facing step: a three-realm forest on quadtrees ​

IDGroupMilestoneBackendsFigureRegression
EV-stepEuler— (#46, quadtree AMR; #66)CPU, FNL (trees leg); CPU only (full leg)yes—

Case and scope ​

The Mach 3 wind tunnel with a step of Woodward & Colella (1984, J. Comput. Phys. 54, 115–173, §IV b): the gas enters from the left at Mach 3, hits a step of height 0.2, and forms a bow shock, a Mach reflection off the top wall and a re-reflection down the tunnel. The tunnel is L-shaped, so FLUME builds it as three rectangular realms glued by two 1:1 mirror seams, and the step is body-fitted: its two faces are physical walls of the realms, with no immersed boundary.

 y = 1   +--------+-----------------------------+   wall
         |   B    |              C              |
  inflow |        | seam                        | outflow
 y = 0.2 +--------+   +------ wall (step top) --+
         |   A    | wall (step front)
 y = 0   +--------+
       x = 0    x = 0.6                       x = 3

The case puts together inter-realm mirror seams (two, on different axes, misaligned), intra-realm quadtree 2:1 seams (refined boxes off the inter-realm seams) and the walls, inflow and outflow of a supersonic tunnel. What it catches:

  • a quadtree that differs from the octree (#46): the same forest on quadtrees (nk = 1) and on octrees with a null z axis must agree column by column to round-off;
  • a z dependence in a 2-D flow: every run must be z-invariant;
  • loss of positivity at the seams, the corner and the reflected shocks;
  • seam defects that show as structure in the quadtree–octree difference map at the inter-realm or 2:1 seams.

The refinement is static

The boxes are placed by hand on the features of the reference solution at t=4, and the grid is frozen after initialisation: FLUME had no runtime AMR when this case was written (milestone M5). A solution-driven marker could not place them either, since the tunnel starts uniform. The boxes therefore follow the flow only once it has settled, and the case verifies the seam machinery, not adaptivity.

Models and numerics ​

ItemChoiceCode
Equationscompressible Euler, ideal gas, γ=cp/cv=3.5/2.5=1.4models
SpaceWENO5 (weno-u-5) flux splitting on characteristic variables; no positivity limiter (refused on multi-realm runs)compute_residuals_weno, adam_flume_cpu_object.F90
TimeSSP Runge–Kutta, 5 stages (runge-kutta-ssp-54), CFL 0.5adam_rk_object.F90
Forestthree realms, two 1:1 mirror seams (A–B at y=0.2, B–C at x=0.6), β cadence, misaligned seam blocks (#51)populate_inter_realm_topology, build_seam_rows, adam_forest_object.F90; numerics
AMRone more level on a static box per realm (geometric box marker, block centroids), quadtree ratio = 4, reflux onmark_by_geometry, adam_flume_common_object.F90; numerics
Thin-block guardblocks thinner than 2ngc along a refined, non-null axis refused (#66)check_amr_block_cells, adam_realm_object.F90
Boundariesinflow, extrapolation (outflow), inviscid walls; realm edges compose the conditions of their facesset_boundary_conditions, adam_flume_cpu_object.F90; realm_edge_face, realm_edge_donor, adam_flume_bc_object.F90; boundary conditions
Corneruntreated (Woodward and Colella reset the entropy near it)—

Initial and boundary conditions ​

RealmExtentFaces
A[0,0.6]×[0,0.2]inflow, wall (bottom), wall (step front), seam with B (top)
B[0,0.6]×[0.2,1]inflow, seam with A (bottom), seam with C (right), wall (top)
C[0.6,3]×[0.2,1]seam with B (left), wall (step top), wall (top), outflow (extrapolation)

The realms share the base cell 1/N. B and C have N/10 blocks per axis, narrow enough to refine close to the seams; A has N/40, so that its blocks keep 8 cells along y: a refined block needs at least 2ngc=6 cells along every active axis.

Itemtrees legfull leg
Base cell1/401/80 (the coarse grid of Woodward and Colella)
Blocks, quadtreeA: 1 block of 24×8; B: 4×4 of 6×8; C: 4×4 of 24×8A: 2×2 of 24×8; B: 8×8 of 6×8; C: 8×8 of 24×8
Treesquadtree (nk = 1) and octree with a null z axis (nk = 4, 16 in A)quadtree
Refined boxes (one level, block centroids)A: none (its single block touches its seam); B: x∈[0.3,0.45], y∈[0.4,0.8]; C: x≥1.2A: y≤0.1; B: x∈[0.3,0.525], y∈[0.3,0.7]; C: x≥0.9 (cells 1/160)
Initial statethe inflow state everywhere: (ρ,u,v,p)=(1.4,3,0,1) (sound speed 1, Mach 3)the same
Final timet=0.5 (440 steps)t=4 (7545 steps); plus the uniform 1/80 control (no box)
Ranks22

The boxes of the full leg, at N=80:

  • A, y≤0.1: the bow shock standing on the lower wall.
  • B, x∈[0.3,0.525], y∈[0.3,0.7]: the bow shock bending up towards the Mach stem. The column x>0.525 touches the B–C seam.
  • C, x≥0.9: all of the realm except the block column on the seam. That covers the reflected shock reaching the step top, the slip line and the re-reflection off the top wall.

A refined block may not touch an inter-realm seam (C's seam is only its face x=0.6; its face y=0.2 is the step top, a wall). The strongest features, the Mach stem and the triple point at x≈0.6, therefore sit on the B–C seam and stay on the base grid. Refining across that seam would take the 2:1 inter-realm coupling (coupling = refined, #52), which is available on octrees only.

Input files ​

FileRole
src/tests/flume/verification/step/make_step.py <dir> --tree quad|oct --cells N --refine --time-max Twrites the manifest step.ini and the realms step-A.ini, step-B.ini, step-C.ini
src/tests/flume/verification/step/check.sh--legs trees (default) and full; --keep keeps the checkpoints for the figures; checks positivity of every run
src/tests/flume/verification/mhd/quadtree/quadtree_oracle.pythe z invariance and the quadtree against the octree per (x,y) column, momentum scaled as one vector
src/tests/flume/verification/make_doc_figures.py (fig_step, fig_step_trees)the figures, from the kept work directories of step/
bash
cd src/tests/flume/verification/step && ./check.sh                    # trees leg, CPU (about 10 min)
FLUME_EXE=$PWD/../../../../../exe/adam_flume_fnl ./check.sh           # trees leg, FNL
./check.sh --legs trees,full --keep                                   # both legs, checkpoints kept
python3 ../make_doc_figures.py --out ../../../../../docs/public/flume --only step step-trees

Results ​

Step forest at t = 0.5 on quadtrees and octrees

trees leg, t=0.5, base 1/40: density on the quadtree and on the octree with the blocks outlined, and the quadtree–octree difference per (x,y) column.

trees legBoundOctree, null z (CPU / FNL)Quadtree, nk = 1 (CPU / FNL)
z spread of a column10−106.1⋅10−13 / 3.1⋅10−130 / 0
against the octree, per (x,y) column10−10—6.5⋅10−13 / 2.7⋅10−13
min ρ, min ppositive, finite0.469, 0.715 (both)0.469, 0.715 (both)

Woodward-Colella step at t = 4

full leg, t=4: density with the blocks outlined (static boxes, inter-realm seams dashed), Mach number, and the zoom on the Mach stem and C's 2:1 seam at x=0.9, refined run against the uniform 1/80 control.

full leg (CPU)BoundResult
min ρ, min p, refined runpositive, finite0.344, 0.370
uniform controlpositive, finitepass

The picture has the features of the reference of Woodward and Colella:

  • the bow shock standing at x≈0.3 on the lower wall;
  • its Mach reflection off the top wall at x≈0.6, with the triple point near (0.6,0.78) and the slip line leaving it along y≈0.8;
  • the reflected shock striking the step top at x≈1.2 in a Mach reflection;
  • its re-reflection reaching the top wall at x≈2.4.

Related cases: Multi-realm runs (the seam legs on Sod), Quadtree AMR (the quadtree on MHD), Ghost probe (the step forest's edge ghosts).

Findings ​

  • The trees order the restriction sums differently (8 fine cells over two identical z layers, against 4), so they agree to round-off, not bit for bit; the octree is z-invariant to round-off only, its tricubic seam weights depending on the z sub-position. The difference map carries no structure at the seams, inter-realm or 2:1.
  • The trees leg takes about 10 min on the CPU, 9 of them for the octree (its blocks split along z too). The full leg is not default: about 41 min on the CPU, plus 13 min for the uniform control.
  • The low-Mach layer along the step top is the numerical boundary layer of the untreated corner, the artifact Woodward and Colella remove with their entropy fix.
  • The zoom compares the refined run with the uniform 1/80 run. The Mach stem and the triple point sit on the B–C seam, on the base grid in both runs, and agree. C's 2:1 seam at x=0.9 is crossed by the reflected shock and the slip line without a kink. Downstream of it, the box resolves the shock pattern near the step top (x≈1.2) more sharply than the uniform grid, which smears it into a single blob.
What this leg caught: blocks thinner than 2 ngc (#66)

A first layout kept A's blocks at 4 cells along y and refined them. The quadtree then differed from the octree by 2.4⋅10−5, with no difference in either tree's z invariance. Bisection put it on the quadtree alone, and only across ranks:

ComparisonMax difference
Quadtree, np 1, against the octree, np 1 or np 22⋅10−14
Quadtree, np 1, against np 24.6⋅10−6 after one step

The difference was independent of seam_ghost_fill and of reflux. At the bisected cell, the coarse ghost density next to the step wall differed by 0.20.

The coarse ghost layers beside a finer block are restricted from 2ngc fine cells. A 4-cell block holds fewer, so the outer layer was restricted from the fine block's own ghost cells, which the same exchange is still filling. They are fresh or a stage stale depending on the exchange order: the local order happened to refresh them first, the MPI path did not. The octree passed only because its rank layout kept the two fine blocks together.

The library now refuses blocks thinner than 2ngc along a refined, non-null axis, the constraint block-structured AMR codes such as PARAMESH impose. No committed case is affected: every one below 6 cells is so only along a null axis, where the field is invariant.