Repository navigation
Take the flap hinge heights from where the contour crosses the crease line - #370
Conversation
…the crease line The nearest point on either side of y = 0 is not a surface height on a cambered section: its lower surface can sit above the chord line at the crease, and the nearest point with y >= 0 can then be on the lower surface too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1-Bort-1
left a comment
There was a problem hiding this comment.
Independent review (advisory)
Verdict: APPROVE WITH COMMENTS · 1 inline, 0 off the diff
Good
- The fix does what the card says:
get_lower_uppernow interpolatesyat every segment crossing ofx = crease_fracand returns the lowest and highest, so the hinge is on the real surfaces (checkedpolar_gen.jl:71-84) - The half-open test
min <= c < maxis right on the edge cases: a vertex on the line counts once in either walk direction, a touching extremum counts zero times, and a vertical segment can never divide by zero (checked by hand on both surface orderings) - No duplication: the only other crossing code,
obj_slice.jl:294, finds leading and trailing edges of a 3D slice, not a height at a chord station - The only callers are
deform_section(common.jl:111) and the legacy test; both pass closed contours, so the newArgumentErrorchanges nothing on any existing path - The function is shorter than the one it replaces, the docstring states what it does with no history, and the file's stray trailing blank line went with it
- The new test is named after the behaviour, uses a cambered section whose lower surface is above
y = 0(the exact failure), states that precondition as an assertion, and covers the open-curve throw - The CHANGELOG entry is compact, user-facing, and says that flapped polars shift
- The card's before/after table and polar deltas, made against a verbatim copy of main in the same session, make the size of the effect judgeable without rerunning anything
Not good
src/airfoil_aero/polar_gen.jl:82— The message says a closed contour crosses 'twice', but the check accepts any count of two or more, and a wavy wrapped canopy can cross four times. A caller who hits the error gets told the wrong rule; 'at least twice' states what the code enforces.turn_trailing_edge!'s legacy branch (polar_gen.jl:30-33) still sorts points into upper and lower surface by the sign ofy, the same wrong assumption this PR removes; the card mentions only that the branch reads the heights, so file it as a note or issueturn_distancein that legacy branch is now the true thickness at the crease, much smaller than the old span; on a thin sectionsmooth_idxcould come back empty, andminimum(smooth_idx)would then throw where it didn't before- The card doesn't say what was searched before writing the crossing loop (rubric §2); the search turns up nothing to reuse, but the card should say so
- The segment from the last point back to the first is never tested; harmless for
crease_frac < 1on wrapped contours, but the docstring says 'closed contour' without saying whether the first point must be repeated at the end
claude, rubric CLEAN_CODE.md. A different lab from the implementer
on purpose: a reviewer sharing its blind spots would not flag its mistakes.
| end | ||
| return lower_trailing_edge, upper_trailing_edge | ||
| n_crossings >= 2 || throw(ArgumentError("the contour crosses x = $crease_frac " * | ||
| "$n_crossings times; a closed one crosses it twice")) |
There was a problem hiding this comment.
MINOR: The message says a closed contour crosses 'twice', but the check accepts any count of two or more, and a wavy wrapped canopy can cross four times. A caller who hits the error gets told the wrong rule; 'at least twice' states what the code enforces.
There was a problem hiding this comment.
Fixed in 87d30de: the message now says 'at least twice'. The docstring also says the segment from the last point back to the first is not tested. The card now says what I searched for, and has a note on the legacy branch's y-sign split and the empty smooth_idx case.
… segments count 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! |
…pper-puts-the-negative-flap-h # Conflicts: # CHANGELOG.md
TL;DR
get_lower_uppernow returns the lowest and highest point where the contour crosses the vertical linex = crease_frac. It used to return the nearest point belowy = 0and the nearest point above it. On a cambered section that lower point sits near the chord line, and the upper point can be on the lower surface.deform_sectionpivots the flap about these heights, so negative deflections turned about the wrong point, and sometimes positive ones did too.What was wrong
On a V3_25 canopy section, wrapped with
ShrinkWrap()asobj_to_yamldoes, the whole lower surface sits abovey = 0at the crease. The nearest point withy < 0is then a stray point near the chord line. And the nearest point withy ≥ 0is whichever surface happens to have a node closer tox = 0.9. On mid-span sections that was the lower surface. So the thread's diagnosis is right but the damage is wider: the upper height, which is thedelta > 0hinge, was also wrong on 5 of the 18 sections.Hinge heights at crease_frac = 0.9, V3_25 `perpendicular_sections(…, 18; n_bins=100)`, wrapped
Bold marks an "upper" height that is the lower surface. After the change the function returns the crossings on all 18 sections.
What changed
The function walks the segments between consecutive points and interpolates
ywherever a segment crossesx = crease_frac. The test is half-open, so a vertex lying exactly on the line counts once. The closing segment, from the last point back to the first, is not tested, and the docstring says so. I searchedsrc/,ext/andtest/for an existing line-crossing or contour-interpolation helper (crossing,intersect,interp,crease_frac) and found none to reuse. It returns the minimum and maximum crossing. Fewer than two crossings throw anArgumentError. That only happens for an open curve, such as an unwrapped slice, and before this change such a curve silently got a hinge aty = 0. Every caller insrc/,ext/andtest/passes a closed contour.Effect on polars
The change is small. On section 9 the lower hinge moves up by 0.0076 c and the upper one by 0.0117 c. With NeuralFoil
mediumat Re = 1e6 and α = 0/5/10°:The "old" row comes from a verbatim copy of main's
get_lower_upper, fed through the same deform, wrap and fit steps in the same session. I left out a before/after figure: a 0.0076 c hinge shift doesn't show at section scale.Where I'd push back
turn_trailing_edge!'s legacy branch, whenthickness_frac === nothing, also reads these heights. Only its own test calls it. It now gets real surface heights too, and that test passes unchanged. That branch still sorts points into upper and lower surface by the sign ofy, which is the assumption this PR removes fromget_lower_upper. Itsturn_distanceis now the real thickness at the crease, which is smaller than the old span. On a thin or strongly cambered sectionsmooth_idxcan come back empty, and thenminimum(smooth_idx)throws. I left the branch alone because no caller outside its own test reaches it. If it is worth keeping, it needs the same crossing-based surface split. Otherwise it can be deleted.#365 edits
deform_sectionand the same test file in a different place. Whichever merges second may need a trivialCHANGELOG.md/ test-file merge. There is no overlap in logic.Verification
(lower, upper) = (−0.00081, 0.00717)against crossings(0.00676, 0.01887).(−0.00025, 0.04049)against the true(0.02141, 0.04039), and noArgumentError. Green after (4/4), and again after 87d30de along with the rest oftest_airfoil_aero.test_airfoil_aero,test_backend_comparison,test_obj_adapter: 163 pass.test_forwarddiff,test_results,test_wake,test_refinement_validation: 58 pass, withtest/generated/rebuilt. All run through juliaserver.agent ci-local, Julia 1.13): PASS in 9 min, exit 0.test_forwarddiff.jl:100on 87d30de (relative_error = 0.046, Julia 1.12 ubuntu), is the test_forwarddiff.jl's POLAR_MATRICES check flakes at ~4%, and the oper #287 flake. I ruled this diff out by measurement: the fixture that assertion builds goes throughdeform_section. Rebuilt under this branch'ssrcand underorigin/main's, its.datfiles, polar matrices and bothlinearizeJacobians were bit-identical.bin/reuse_lint). Merged withorigin/mainin f0765eb.ArgumentErrorwhere it used to get a silent hinge aty = 0.Scope
+35 / −21 across 3 files, 87d30de being the review round (error message and docstring only). The function body is smaller than the one it replaces. The rest is a 15-line test and a changelog entry.
Closes #364 · task
VortexStepMethod.jl-364