Maxwell-accommodating wall boundary conditions (opt-in :wall face)#26
Merged
Conversation
…l face)
Adds grid-aligned kinetic walls, the capability gap that blocked microflows entirely --
slip, temperature jump and the Knudsen layer ARE the physics there -- and that also
blocked Couette/Fourier validation. Opt-in via a new :wall face type; defaults unchanged
and no golden moves.
PHYSICS. A wall is a HALF-SPACE moment problem and a 35-moment vector cannot encode the
split, so the ghost-cell form is an approximation -- but two of its three ingredients are
exact:
M_ghost = alpha * M_Maxwellian(rho_w, u_w, T_w) + (1-alpha) * M_specular(M_int)
* specular (alpha=0) is EXACT: reflection maps v_n -> -v_n, i.e. M_{ijk} -> (-1)^i
M_{ijk}, a sign flip on moments of odd normal order. Measure-preserving, so it takes
a realizable state to a realizable state with no approximation, and tangential
velocity passes through untouched (free slip).
* diffuse (alpha=1) sets rho_w from zero net normal mass flux, with the incoming flux
from a half-space Gaussian integral (closed form in erf/exp). THIS Gaussian
assumption is the one real approximation in the design.
* the blend is CONVEX, so realizability follows from the same argument bgk_relax_tup
and the theta*-IDP limiter already rest on. No projection, no new failure mode.
Halo-refill only: NO changes to the residual, WENO5, theta*-IDP or the flux kernels, so
it works at every spatial order and on GPU immediately.
Ghost layer k MIRRORS interior layer k rather than copying the nearest interior cell
(what :outflow does). Specular reflection of a half-space IS the mirror map, so ghost
layer k must see the interior cell at the same distance from the wall -- load-bearing at
order 3, where g=8. On the GPU this is why _axis_src returns a mirrored index plus a
wall_side flag instead of a plain index remap: unlike :inlet, whose ghost is a CONSTANT
vector, a wall ghost is a FUNCTION of the adjacent interior cell.
VERIFICATION:
- equilibrium wall (T_w = T, at rest) is an EXACT fixed point -- max|dM|/|M| = 0.000e+00
on BOTH CPU and GPU, bitwise, not merely small. This is the test that catches a wrong
rho_w normalization: a factor error in the half-space mass balance shows up here and
nowhere else, so landing at exactly zero says the balance closes analytically.
- specular wall: mass drift 0, energy drift 0, tangential velocity preserved at exactly
0.300, with T_w = 99 deliberately absurd to prove it is ignored.
- half-space influx closed form vs numerical quadrature: 3.3e-7 (independent computation,
the same tactic used on the Isserlis table).
- unit gates W1-W5: 265/265, registered in runtests.jl so CI runs them.
- full suite 1689 passed / 5 broken / 0 failed / 0 errored = 1424 baseline + 265 new;
stdout diffed against baseline is identical apart from the new tests' own output.
ALSO FIXED, all found while finishing this:
- walls were UNREACHABLE by users. simulation_runner never populated WALL_SPEC, so the
feature only worked if a caller poked the global directly (as the tests did). Now wired
via a `wall_spec` param, with a warning if a :wall face is set without one. Verified
end-to-end through the runner.
- test_wall_bc.jl was not registered in runtests.jl, so CI would not have run it.
- HIGHORDER.md -- the doc handed to Fox and Posey -- was a full generation stale: it
described itself as notes on the `projection35-port` branch, listed spatial_order as
only 1 or 2, and said the scheme was "not yet robust at Ma=100". Order-3 has been the
DEFAULT since #18 and Ma=100 is CI-guarded. Refreshed with dated correction notes rather
than silent edits, keeping the Ma=100 failure-mechanism paragraph because the
cancellation in u = M100/M000 at rho~1e-5 is still what to understand when a high-Ma run
misbehaves. Also added the options table it was missing entirely: Pr, omega,
stage_bgk_exact and :wall/wall_spec were documented nowhere a collaborator would look --
someone could match omega to argon, get Pr right, and still have mu 1.85x low with no
indication anything was wrong.
SCOPE / NOT DONE: grid-aligned faces only, stationary in the normal direction (tangential
motion allowed, which covers Couette/Fourier/planar microchannel). Immersed and curved
walls are a separate spec -- that is what would fix the cylinder case's held-gas
bounce-back. The slip coefficient is MEASURED, not asserted, by
test/validate_wall_slip.jl: the Gaussian half-space assumption may not reproduce Maxwell's
sigma_p ~ 1.0-1.1, and if it is badly off the escalation is a prescribed wall flux
(KFVS-at-wall), which would have to touch the residual and the theta*-IDP anchor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds grid-aligned kinetic walls — the capability gap that blocked microflows entirely (slip, temperature jump and the Knudsen layer are the physics there) and also blocked Couette/Fourier validation. Opt-in; defaults unchanged, no golden moves.
Physics
A wall is a half-space moment problem, and a 35-moment vector cannot encode the split. The ghost form is therefore an approximation — but two of its three ingredients are exact:
v_n -> -v_n, i.e.M_{ijk} -> (-1)^i M_{ijk}, a sign flip on moments of odd normal order. Measure-preserving, so realizable in, realizable out, with tangential velocity untouched (free slip).rho_wfrom zero net normal mass flux, the incoming flux being a closed-form half-space Gaussian integral. This Gaussian assumption is the one real approximation.bgk_relax_tupand theta*-IDP already rest on — no projection, no new failure mode.Halo-refill only: no changes to the residual, WENO5, theta-IDP or the flux kernels*, so it works at every spatial order and on GPU immediately.
Ghost layer k mirrors interior layer k rather than copying the nearest cell — specular reflection of a half-space is the mirror map, which is load-bearing at order 3 (g=8). On GPU this is why
_axis_srcreturns a mirrored index plus awall_sideflag: unlike:inlet, whose ghost is a constant vector, a wall ghost is a function of the adjacent interior cell.The slip coefficient — measured, and it works
The design deliberately left open whether the Gaussian half-space assumption reproduces Maxwell slip. It does:
The (2-alpha)/alpha accommodation scaling is reproduced, and
sigma_p= 0.95–1.19 against a theoretical 1.0–1.1. Interior profiles linear to R^2 = 0.99999.So no escalation is needed. Had this been badly off, the fix would have been a prescribed wall flux (KFVS-at-wall), touching the residual and the theta*-IDP anchor. It isn't.
lambdauses the shared conventionlambda_mu = mu/(rho sqrt(2RT)) = tau_ref*sqrt(Theta/2)— the same one bridged to SPARTA, so the number is comparable across codes.Verification
max|dM|/|M| = 0.000e+00on both CPU and GPU, bitwise. This is the test that catches a wrongrho_wnormalization: a factor error in the half-space mass balance shows up here and nowhere else, so exactly zero says the balance closes analytically.T_w = 99set absurdly to prove it is ignored.runtests.jl.Also fixed — all found while finishing this
simulation_runnernever populatedWALL_SPEC, so the feature only worked if a caller poked the global directly, as the tests did. Now wired via awall_specparam, with a warning if a:wallface is set without one. Verified end-to-end through the runner.test_wall_bc.jlwas not inruntests.jl— CI would not have run it.HIGHORDER.mdwas a generation stale — the doc handed to Fox and Posey. It called itself notes on theprojection35-portbranch, listedspatial_orderas only 1 or 2, and said the scheme was "not yet robust at Ma=100". Order-3 has been the default since High-order WENO5 + θ*-IDP (CPU+GPU, DRY) — order-3 as default #18 and Ma=100 is CI-guarded. Refreshed with dated correction notes, keeping the Ma=100 failure-mechanism paragraph (the cancellation inu = M100/M000at rho~1e-5 is still what to understand when a high-Ma run misbehaves). Also added an options table it lacked entirely —Pr,omega,stage_bgk_exactand:wall/wall_specwere documented nowhere a collaborator would look, so someone could match omega to argon, get Pr right, and still havemu1.85x low with no warning.Scope / not done
Grid-aligned faces, stationary in the normal direction (tangential motion allowed — covers Couette, Fourier, planar microchannel). Immersed and curved walls are a separate spec — that is what would fix the cylinder case's held-gas bounce-back and its ~10% blockage.