Skip to content

Reconstruct NeuralFoil's surface pressure from edge velocity in arc length - #266

Open
1-Bart-1 wants to merge 1 commit into
mainfrom
nf-surface-closure
Open

Reconstruct NeuralFoil's surface pressure from edge velocity in arc length#266
1-Bart-1 wants to merge 1 commit into
mainfrom
nf-surface-closure

Conversation

@1-Bart-1

Copy link
Copy Markdown
Member

The bug

NeuralFoil samples ue/u∞ at the cell centres of a uniform chordwise grid
(compute_optimal_x_points), so with 32 stations per surface the first sits at
1.5625% chord and the last at 98.4375%. Nothing is reported at either end.
neuralfoil_contour_solution filled those gaps by extrapolating Cp linearly off
the end of each surface, independently.

Through a stagnation point the inviscid surface speed is linear in arc length, so
Cp = 1 − ue² is quadratic. Extrapolating Cp runs a straight line backwards
through the curve's own turning point. On an SK100 mid-span section at 5°:

old new XFoil, same contour
max Cp (stagnation, must be 1) 0.689 1.000 0.999
Cp at the leading edge −1.595 +0.766 +0.413
Cp at TE, upper / lower 0.057 / 0.117 0.093 / 0.093 0.181 / 0.181
integrated drag (reported 0.0276) −0.0199 +0.0269

Cp cannot exceed 1, and the two trailing-edge values must be equal on a sharp
edge (Kutta). Chord fraction is also the wrong coordinate across a blunt nose: the
unsampled region is 4.1% of arc against 1.6% of chord.

The fix

Interpolate ue, in arc length, over both surfaces as one curve:

  • Signing the lower surface negative joins them through the stagnation point, where
    ue = 0 by definition. The nose is then interpolated between the innermost
    station on each side
    rather than extrapolated off the end of one, and Cp
    reaches exactly 1 at stagnation without that being imposed — including the fact
    that stagnation sits on the lower surface at positive incidence, not at the nose.
  • The stagnation point goes in as its own knot, where the two innermost stations
    interpolate linearly to zero. That placement is the stagnation-point-flow result,
    not a fit, and it stops the cubic guessing the region's width from two distant
    samples.
  • The trailing edge takes the mean of the two surfaces' extrapolated speeds — Kutta.
  • Between stations, a shape-preserving monotone cubic (FritschButland), the family
    NeuralFoil's own training pipeline resamples XFoil boundary layers with.

neuralfoil_section now also returns ue_upper/ue_lower.

No new dependencies; FritschButlandMonotonicInterpolation is in Interpolations.

Honest limits

The lift integral loses about a point (Cl_int 0.934 → 0.919 against a reported
0.949), and on smooth sections whose true drag is small the traction integral now
overshoots (0.027 against 0.009) rather than coming out negative. Both are much
smaller than the sign inversion they replace, but they are real.

This changes nothing about NeuralFoil's integrated CL/CD/CM, only the
distribution reconstructed on the contour — which matters to anything integrating
the surface traction, e.g. a structural coupling.

Not verified locally

Both changed files parse and the reconstruction was exercised against XFoil on four
SK100 section variants. The suite is left to CI.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…ength

NeuralFoil samples at the cell centres of a uniform chordwise grid, so it reports
nothing over the first and last 1/2N of chord -- the nose, which is almost all of
the axial force, and the trailing edge. The old reconstruction extrapolated Cp
linearly off the end of each surface, independently.

Through a stagnation point the inviscid surface speed is linear in arc length and
Cp = 1 - ue^2 is quadratic, so extrapolating Cp runs a straight line through the
curve's own turning point. On an SK100 mid-span section at 5 deg that put
Cp = -1.60 at the leading edge, where it has to approach +1, and left the two
surfaces at 0.057 and 0.117 at the trailing edge where a sharp edge carries one
pressure. Chord fraction is also the wrong coordinate there: the unsampled nose is
4.1% of arc against 1.6% of chord.

Interpolate ue instead, in arc length, over both surfaces at once. Signing the
lower surface negative makes them one continuous curve whose zero is the
stagnation point, so the nose is interpolated between the innermost station on
each side rather than extrapolated off the end of one, and Cp passes through
exactly 1 at stagnation without that being imposed -- including the fact that
stagnation sits on the lower surface at positive incidence. The stagnation point
goes in as its own knot, placed where the two innermost stations interpolate
linearly to zero, which is the stagnation-point-flow result rather than a fit. The
trailing edge takes the mean of the two surfaces' extrapolated speeds, the Kutta
condition. Between stations the interpolation is a shape-preserving monotone cubic,
the family NeuralFoil's own training pipeline resamples XFoil boundary layers with.

Measured on that section, integrating the surface traction: max Cp goes from 0.689
to 1.000, leading-edge Cp from -1.60 to +0.77 (XFoil 0.41), the two trailing-edge
values from 0.057/0.117 to a matched 0.093, and the integrated drag from -0.0199,
the wrong sign, to +0.0269 against NeuralFoil's own reported 0.0276.

The lift integral loses about a point of accuracy (Cl_int 0.934 -> 0.919 against a
reported 0.949), and on smooth sections whose true drag is small the integral now
overshoots rather than inverting. Both are far smaller than what they replace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@1-Bart-1
1-Bart-1 force-pushed the nf-surface-closure branch from 09b607e to 5b60042 Compare August 25, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant