Skip to content

deform_section's re-wrap turns a thin section into a contour whose surfaces cross #321

Closed

Description

@1-Bort-1

deform_section shrink-wraps the shape it is given even at delta = 0, with the default ShrinkWrap(clearance=0.0). On a section that has already been wrapped once and is thin, that second wrap produces a curve whose upper and lower surfaces cross each other over most of the chord. It is not an airfoil, so neither backend has a meaningful answer for it: XFoil's panel code can terminate the process on one — the branch agent/BeyondTheSim.jl-53 guards against being handed it — and NeuralFoil will answer from a Kulfan fit of a self-crossing curve without saying anything is wrong.

How it shows up

One mesh section of a kite wing, sliced from its .obj and wrapped once with the wing's own mesh: settings, gives a clean contour: 239 nodes, zero crossings, 32° maximum turn between panels. Running that same raw point cloud through shrink_wrap and then deform_section(x, y, 0.0) gives 239 nodes again and, depending on the rolling-ball radius, 29 to 60 crossing panel pairs, with the contour doubling back on itself exactly (a 180.0° turn) at every radius from 0.15 up:

min_concave_radius crossing panel pairs max turn lower surface monotone
0.05 34 45.0° no
0.10 34 48.3° yes
0.15 60 180.0° no
0.20 58 180.0° no
0.30 48 180.0° yes
0.40 29 180.0° yes
0.60 29 180.0° yes
0.80 35 180.0° yes
one wrap only, no deform_section 0 32.3° yes

The last row is the same cloud through a single shrink_wrap, so the tangle is made by the second wrap rather than present in the slice.

The section is a thin, strongly cambered one near mid-span; clearance is 0.0, so the wrap hugs the cloud and the rolling ball has very little room between the two surfaces.

What I would do

Either have deform_section skip the re-wrap when the shape it is handed is already a clean wrap, or have shrink_wrap refuse to return a contour that crosses itself rather than returning one. Which of the two is right depends on whether a caller is ever meant to wrap an already-wrapped contour at all, and either way it changes the geometry every generated polar is computed on, so it wants a decision rather than a patch.

I have not started this. Found while fixing 1-Bart-1/BeyondTheSim.jl#53, where the crossing contour ended the Julia process inside XFoil.

From 1-Bart-1/BeyondTheSim.jl#53 · task BeyondTheSim.jl-53

Activity

  1. 1-Bort-1 commented on Sep 21, 2026

    @1-Bort-1
    MemberAuthor

    Making the default wrap stop warning on V3, in #365: shrink_wrap cuts the loops the clearance offset makes on thin canopy sections (#363) before resampling, so the default MeshSettings give a simple contour. Default clearance and radius stay as they are.

  2. 1-Bart-1 commented on Sep 21, 2026

    @1-Bart-1
    Member

    Why is rewrap failing? And is this only failing at delta=0? Delta=0.01 would also need a rewrap and that cannot be avoided right? Or doesn't it need a rewrap ever.

  3. 1-Bort-1 commented on Sep 21, 2026

    @1-Bort-1
    MemberAuthor

    No, it is not specific to delta=0. The same section crosses at every delta: on mid-span section 10 of V3_25.obj I got 41-70 crossing panel pairs at delta = 0, 0.01°, 0.1°, 1°, 5°, −5° and 15°. The flap rotation (turn_trailing_edge!) is not the cause. Rotating without re-wrapping gave 0 crossings at every delta I tried.

    Why the re-wrap fails: deform_section (src/airfoil_aero/airfoil_solvers/common.jl:115) always re-wraps with the default ShrinkWrap(clearance=0.0). That means a rolling ball of radius 0.02, whatever radius the first wrap used. shrink_wrap treats its input as an unordered point cloud. The first wrap of a single-skin canopy gives a contour only ~0.002 thick, with panels up to 0.09 long. Between two nodes a distance h apart, a ball of radius r dips about h²/8r below the line joining them. Once panels are longer than ~0.018, that dip is more than the 0.002 thickness, so the ball falls between neighbouring nodes and touches the other surface. The ball only grows to span the largest gap between neighbouring points, and here every point has a partner on the other surface 0.002 away, so it stays at 0.02. The trace switches between upper and lower surface 18-74 times. Resampling that pinched loop into two halves then produces the crossing panels.

    Does a nonzero delta need a re-wrap? Not to prevent crossings. The rotation keeps the node count, so an already-wrapped input needs no wrap for that either. What the wrap does add is a fillet at the crease: rotation alone left a 163° fold at δ = −15° on a synthetic section. So delta ≠ 0 needs something to smooth the crease, not a second rolling-ball pass over the whole contour.

    Re-wrapping with a ball at least as large as the longest panel removes the tangle: r = 0.1 gave 0 crossings on all 18 sections. Re-using the caller's own wrap settings gave 0 on 12 of 18 and 2-4 on the other 6. So the fix I would make is: no rolling-ball pass in deform_section at all, and local smoothing at the crease when delta ≠ 0. The simpler alternative is a ball radius floored at the longest input panel. Both change every generated polar, so tell me which one and I will build it here.

    Separate find: get_lower_upper (polar_gen.jl:68) takes the y < 0 point nearest the crease as the lower surface. On these cambered sections that is y ≈ −0.0001, so for negative delta the hinge sits near the chord line rather than on the lower surface.

  4. 1-Bart-1 commented on Sep 21, 2026

    @1-Bart-1
    Member

    The ball used on the rewrap should be the same as the ball on the first pass, the rewrap should automatically use the same settings. And there should be a warning or maybe an error if the ball is too small for the panels. And just putting the default min radius higher solves this, without increasing distance or giving a round trailing edge?

  5. 1-Bort-1 commented on Sep 21, 2026

    @1-Bort-1
    MemberAuthor

    Done in 85652b3. The re-wrap now uses the first pass's ball automatically, at zero clearance. Re-applying the clearance would pad the section twice. shrink_wrap also warns, naming the radius, when the contour it returns crosses itself.

    The same ball alone was not enough: at r = 0.2, 6 of 18 V3 sections still crossed, because the first wrap leaves 0.08–0.1 panels that even that ball bulges past. So shrink_wrap now also rolls the ball on the polygon of a closed input rather than only on its nodes. With both, 0 of 72 section × delta cases cross at every radius from 0.02 to 0.4.

    Raising the default radius does not give a round trailing edge. TE thickness stays 0.0020 on V3 at every radius; only clearance rounds corners. It does add distance: the wrap moves away from the cloud at the tube–canopy junction, up to 0.014–0.016 at r = 0.02 and 0.068–0.089 at r = 0.4. And on its own it does not solve this: sections 7 and 14 still crossed at r = 0.4. So I left the default at 0.02.

    The warning does fire on the default mesh settings on 6 V3 sections. That comes from the 0.006 clearance offset crossing itself, not from the ball: #363. The hinge find from before is #364.

  6. 54 remaining items

  7. added and removed on Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions