Repository navigation
IBM: extrapolate hot/reacting-wall ghost state from where the image point is actually sampled - #1969
sbryngelson wants to merge 1 commit into
Conversation
…nt is actually sampled The hot/reacting-wall ghost state used the mirror phi_g = 2 phi_s - phi_IP, which assumes the image-point value sits |levelset| in front of the wall. The inverse-distance interpolation weights skip solid cells, so for ghost points near the surface the value is sampled ~1 dx farther out and the ghost overshoots: isothermal walls were imposed 85-210 K too hot on a Mach-1.5 rod, and a 3D shock-particle-curtain case went NaN. The surface-reaction solve used the same wrong gradient length. Store the wall distance of the weighted stencil centroid (ghost_point%ip_dist) and use d = max(ip_dist, |levelset|) as the surface-solve gradient length and |levelset|/d as the maximum ghost extrapolation weight. Regenerates the 2D ibm_reacting_surface example golden (F52F0D4C) and adds a 2D hot, non-reacting IB cylinder test (204838D0) that pins the thermal ghost path.
Lines of Code
|
084a14b to
b1719ba
Compare
|
Validation from a particle-resolved IB campaign on Tuolumne (MI300A); build = master a6add01 + #1953, #1955, #1956, #1957, #1962 and this PR. These runs check the fixed Nusselt number, isothermal wall (Tw/T∞ = 1.1, 330 K in 300 K moist air, M = 0.2, gas reactions off)
Churchill–Bernstein gives the same picture (within 3 % at 40 cells/D).
Hot wall, reacting (2D cylinder, Tw = 1400–3000 K in 1000 K air, 16 cells/D, Caveats:
Made with Claude Code. |

Contribution Policy
We do not accept pull requests generated primarily by AI without genuine understanding or real-world usage context.
All contributions are expected to demonstrate:
If these expectations are not met, we would prefer to implement the changes ourselves rather than spend time reviewing low-effort submissions.
Acknowledgement
PR template credit: junegunn
Summary
Fixes the ghost state at isothermal (
thermal_bc = 1) and reacting (surface_reaction = 1) IB walls in chemistry runs (#1821). Before this fix, near-surface ghosts were too far from Twall, and the surface-reaction solve used the wrong gradient length.Mechanism
s_blend_ghost_statebuilds the ghost value as the linear mirrorphi_g = phi_s + theta*(phi_s - phi_IP)withtheta = 1. That is only correct ifphi_IPis sampled |levelset| in front of the wall.s_compute_interpolation_coeffsuses inverse-distance weights that drop solid stencil cells. For a ghost point near the surface, the mirror point lies inside the ghost's own (solid) cell, sophi_IPactually comes from fluid cells about 1 dx farther out. The ghost then gets roughly2 T_s - T(~1 dx)where it should get aboutT_s. At a hot wall in cold gas that is several hundred K too hot.s_ibm_correct_statealso passes|levelset|as the gas-side gradient lengthdto the surface solve. At these points that overestimates the gradient, so the surface fluxes are too large as well.Fix
ghost_point%ip_diststores the wall distance of the weighted stencil centroidsum c_i x_i, which is where the image-point value is actually sampled. It is computed ins_compute_interpolation_coeffsby scalar accumulation. An array-constructor version gave garbage inside the offload loop on MI300A.s_ibm_correct_statesetsd = max(ip_dist, |levelset|).dis the surface-solve gradient length.|levelset|/dis passed tos_blend_ghost_stateastheta_max, the linear-extrapolation weight. It is at most 1 and equals 1 for an ideal mirror. The existing temperature-window and species-positivity limits still apply on top.T_s = T_IPandYs_s = Ys_IP, theta has no effect.How it was found
A 3D Mach-2 shock hitting a curtain of 413 moving reacting spheres (12 cells/D, 1800 K walls) went NaN at about step 200. Isolation runs ruled out motion, collisions, the wall-temperature model, surface chemistry, the transport time step, and CFL; halving CFL gave NaN at the same physical time and cell. The failure needed a hot isothermal-type wall in 3D. The NaN cells were in narrow gaps (3–5 cells) between neighbouring spheres. In those gaps, first fluid cells sitting on the surface in staircase notches had over-hot ghosts on 2–3 faces and were heated to 3000–4080 K before blowing up. Ghosts with levelset ≈ 0 held about 2850 K against an 1800 K wall, and the mean ghost T did not fall toward Twall as levelset → 0. With the fix, the same case runs to t_stop, and a 5x longer variant also completes. At the old failure time, the hottest near-wall fluid cell is about 2190 K.
Verification
The verification runs (1 node x 4 MI300A, Tuolumne) were done on a development branch that has this fix on top of master plus unmerged IB thermal features (thermal layer, lumped wall temperature). This PR ports only the ghost-distance change. The resolved Q1/Q2 rod cases use only
thermal_bc = 1andsurface_reaction, which master has. Case A uses--thermal-layer 0.1, and the 2D curtain usesthermal_bc = 3; both are from the unmerged features. OLD = before the fix, NEW = with the fix.Implied wall temperature. For each fluid/ghost face pair, T is interpolated linearly in levelset to the zero crossing. This is the wall temperature the discrete profile actually imposes. Results are front-half means.
Resolved rod (Mach 0.2, Re_D = 471, isothermal 1800 K wall, T∞ = 496 K; Q1 non-reacting, Q2 with surface reactions):
The OLD error decays as about h^0.8. NEW's is about 15x smaller and decays as about h^2.6.
Case A (Mach 1.5, Re_D = 5.4e4, reacting, 1800 K; boundary layer unresolved at 2–4 cells):
OLD imposes a wall 85–210 K too hot at every resolution tested. NEW converges onto Twall.
Heat flux, resolved non-reacting rod (Q1). Q_cons is the heat the IB injects, from a global energy balance; two box sizes agree to 0.5%. Q_fit is the gas-side gradient flux.
Carbon flux, resolved reacting rod (Q2). Regression rate is the mean over t* = 2.5–4.
NEW is grid-converged to 0.3%. OLD drifts by +4.9% and moves away from NEW as the grid is refined. This is consistent with the bug: the gradient-length error is an O(1) factor at the affected ghost points, not O(dx). An offline replica of the weights on the case-A rod shows that 23–27% of ghost points have d/|levelset| > 2 at every resolution from 40 to 200 cells/D.
Case A burning rate and heat flux.
The burning rate drops by 19–24%. The wall heat flux through the staircase changes much less (0–10%).
2D shock-curtain smoke run (38 particles, 12 cells/D, 1800 K): total carbon loss goes from 4.952e-3 to 4.344e-3 kg/s/m (−12.3%). Mean near-wall gas is 80–220 K cooler.
What this does not address
Tests
CPU,
./mfc.sh test --no-mpi --no-gpu -j 24:--only IBM: 61/61 pass, unchanged.--only Chemistry: 23/23 pass after the golden changes below.Goldens:
2D -> Example -> ibm_reacting_surface, regenerated). This is a 1200 K reacting carbon cylinder; the suite runs it on a 26x26 grid (about 4 cells across the rod) for 1.27 ms. It goes through exactly the changed path, so its solution moves throughout the wake. The largest absolute change is 9.29e4 in energy (rel 1.78, a ghost cell). The largest relative change is 2.1e2, at a near-zero value. This is the only existing golden in the IBM and Chemistry suites that moved.ip_distis computed for every IB ghost point but is only read in the chemistry branch ofs_ibm_correct_state, so other goldens should not move. The full suite was not run locally.2D -> Chemistry -> Isothermal Wall -> IBM Hot Cylinder, new). This is a 1500 K non-reacting IB cylinder in 300 K h2o2 gas, 50x50, 20 steps, tol 1e-6, with no new mechanism. It pins the thermal ghost extrapolation, which had no registered case. Run against the pre-fix source, it fails with energy differing by up to 5.1e4 (12% of the field range) and density by up to 2.2e-2 (7%) in near-wall and ghost cells. A golden can detect a change in this path but cannot by itself assert that the wall temperature is correct. That check is the Timp convergence study above../mfc.sh formatand./mfc.sh precheckpass.