Take the panel normal from the quarter-chord step - #273
Open
1-Bart-1 wants to merge 2 commits into
Open
Conversation
panel_axes built z_airf as cross(x_airf, le_1 - le_2) while the bound vortex, width and y_airf all come from panel_span_vector. On a panel whose two sections have differently-directed chords the normal was not square to the vortex the loads are built from, and alpha is measured against that normal, so every panel coefficient inherited the error. The frame now closes as z_airf = x_airf x y_airf, which is what the Panel field docstring already described. Taper alone never triggered it: (le_1 - le_2) - span_vec is a quarter of chord_vec_2 - chord_vec_1, purely chordwise when the two chords are parallel, and cross(x_airf, .) annihilates it. Twist, sweep and dihedral do trigger it. The reference implementation makes the same mix, so it moves with the code: its normal now comes off the bound filament it already builds. Its three wings barely exercise the difference - the elliptical one separates the two steps by 34 degrees and still cannot see it, being planar - so the new panel test states the invariant directly on a swept, twisted panel where the two definitions are 13.7 degrees apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
1-Bart-1
commented
Sep 5, 2026
| Airfoil frame and size of the panel between two sections, as | ||
| `(; x_airf, y_airf, z_airf, chord, width)`. | ||
|
|
||
| `x_airf` is chordwise and `y_airf` runs along the quarter-chord line the bound |
Contributor
|
Picked up as |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VwDM1xm13gZVnFf9ha2JcT
Contributor
FixedThe Changes
Verification
Commits
Task |
1-Bort-1
reviewed
Sep 6, 2026
1-Bort-1
left a comment
Contributor
There was a problem hiding this comment.
Independent review (advisory)
Verdict: APPROVE · 0 inline, 0 off the diff
Good
- The one-line fix
cross(x_airf, span_vec)is mathematically sound:z_airf = orient·(x×y)exactly equals the documentedx_airf × y_airf(normalised), verified againstpanel.jl:28andpanel_span_vector(quarter-chord step). - The docstring rewrite removes the stale
chord_weightrationale (a "why") and states what each axis is, matching rubric §4; thex_airf × y_airfnormalised claim is exactly what the code computes. - The new test states the invariant independently of the oracle — square to vortex/chord,
z = x×yclosure,orientflips — plus a guard (separation > 5) so it cannot decay into testing nothing.
Not good
- The matching
build_panel_force_eqs/wagner_reference_framechange in SymbolicAWEModels.jl is deferred with no linked issue/task, so the two repos risk silently diverging onz_airf. - The
orienttest passeschord_weight=0.5positionally (line 202), burying a magic number that duplicates the signature default.
opencode, rubric CLEAN_CODE.md. A different lab from the implementer
on purpose: a reviewer sharing its blind spots would not flag its mistakes.
Contributor
|
Local full suite: PASS (6 min, Julia 1.12.7, one cell of the matrix) |
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.
Fixes #272.
panel_axesbuilt the panel normal from the leading-edge step:The bound vortex,
widthandy_airfall come from the quarter-chord step, soz_airfwas the odd one out. On a panel whose two sections havedifferently-directed chords the normal is then not square to the vortex the loads
are built from, and since
alpha = atan(v·z_airf, v·x_airf)feeds every polarlookup, the error propagates into
cl,cdandcmfor that panel.One character of the fix:
cross(x_airf, span_vec). The frame now closes asz_airf = x_airf × y_airf, which is what thePanelfield docstring(
src/panel.jl:28) has always claimed.Why it went unnoticed
Taper alone cannot trigger it.
(le_1 - le_2) - span_vecequals¼(chord_vec_2 - chord_vec_1), which is purely chordwise when the two chords areparallel, and
cross(x_airf, ·)annihilates the chordwise part exactly. It takestwist, sweep or dihedral — something that changes the chord direction between
the two sections — for the normals to separate at all.
The reference wings barely do that:
:rectangular:curved(y, z):elliptical±ẑregardlessThe elliptical wing separates the two steps by 34° and still cannot see the
difference. Nothing in the suite combines sweep with a changing chord direction,
which is the only regime where the choice matters.
Changes to the reference oracle
test/thesis_oriol_cayon.jlmakes the same mix (itsx_airfis the normal, itsz_airfthe spanwise axis):so the inconsistency is inherited from the original formulation rather than
introduced by the port, and the oracle has to move with the code or it pins the
old convention. It now takes the normal from the bound filament it already builds
— a two-line change that reuses
bound["x2"] - bound["x1"]instead of recomputingfrom the leading edges.
This is the part worth reviewing carefully, since it is the test changing to
match the code. It is defensible here because the oracle's own spanwise axis is
already the quarter-chord step, so the change makes it self-consistent rather than
merely agreeing with us. Without it, 156 assertions fail (2 models × 39 panels × 2
asserts, all on
:rectangular) at ~0.25° — real but small.To avoid leaning on the oracle for the thing being fixed, the new test in
test/panel/test_panel.jlstates the invariant directly on a swept, twisted panelwhere the two definitions are 13.7° apart: the normal is square to the bound
vortex and to the chord, the frame closes as
z = x × y, andorientflipsyand
ztogether. It carries a guard asserting the geometry actually discriminatesthe two definitions, so it cannot silently decay into a test of nothing.
Measured effect
SK100 leading-edge-inflatable kite, 44 panels, outermost rib bay raked 58–68°,
where the old and new normals are 5.6–13.8° apart. Coupled beam + VSM flight,
identical settle (1200/1200 steps):
z_crossfromle_1 - le_2span_vecSame failure mode either way — a tip-stall divergence — so the frame error
aggravates it rather than causing it, but it is worth ~55% more flight time here.
Deliberately not included
Orthogonalising
y_airfagainstx_airf. It measures better on the kite (217steps), but that metric records how long a stall divergence is deferred, not
accuracy, and both of
y_airf's uses argue for keeping the raw quarter-chorddirection:
dir_liftis Kutta–Joukowski (F = ρ v × Γ,Γalong the boundvortex), and
q_dyn = ½ρ|v × y|²is the simple-sweep normal-to-quarter-chordcomponent. Settling that needs a swept, tapered validation case with a known
answer, which does not exist in the suite yet. Left open on #272.
Downstream
SymbolicAWEModels.jl rebuilds this same expression symbolically in
build_panel_force_eqsand again inwagner_reference_frame. Those need thematching change or its symbolic force assembly disagrees with this solver.
🤖 Generated with Claude Code