Skip to content

Optional flow-curvature pitch-rate moment - #260

Merged
1-Bart-1 merged 5 commits into
mainfrom
feat/flow-curvature
Aug 17, 2026
Merged

Optional flow-curvature pitch-rate moment#260
1-Bart-1 merged 5 commits into
mainfrom
feat/flow-curvature

Conversation

@1-Bart-1

@1-Bart-1 1-Bart-1 commented Aug 17, 2026

Copy link
Copy Markdown
Member

Adds an opt-in flow_curvature solver setting (default false) giving each
section the thin-airfoil pitch-rate moment increment, driven by a per-panel rate
so deformation modes reach it.

What is missing today

A section rotating about its own spanwise axis at rate q sees an incidence that
varies linearly along the chord, α_eff(x) = α + q(x − x_p)/V. Thin airfoil theory
cannot tell that apart from parabolic camber, so the Fourier coefficients pick up

A₀ = α + (q/V)(c/2 − x_p),   A₁ = (q/V)(c/2),   A₂ = 0

The lift half is already exact in VSM: Cl = 2π(A₀ + A₁/2) = 2π[α + (q/V)(3c/4 − x_p)]
is just the effective incidence at three-quarter chord — precisely where set_va!
samples the inflow (control_points = LE·0.25 + TE·0.75). Nothing to fix there.

The moment is not, because it lives in A₁ rather than A₀:

Cm_c/4 = (π/4)(A₂ − A₁) = −(π/4) q̂,    q̂ = q c / (2 v_rel)

One control point per section can represent an incidence but not an incidence
gradient. A chordwise-refined VLM recovers this from the discretisation; a
lifting line has to add it analytically. It is independent of the pivot (x_p
only enters A₀), so only the rate is needed — the arm effect is already handled
by the existing (aero_center − reference_point) × F sum.

Per-panel rates

What the moment responds to is the chordwise gradient of normal velocity across a
panel. For rigid motion that gradient is ω ⋅ y_airf, but a deforming wing has a
twist rate that varies along the span and no single body rate expresses it — which
matters because this moment is largest exactly there (a strip's torsional inertia
is small while the moment scales with ).

So the input is the gradient, not a body rate:

  • pitch_rate_dist on BodyAerodynamics, one rate per panel, positive nose-up.
  • set_va!(body_aero, va, omega) fills it by projecting onto each y_airf, so
    panels at different dihedral see different rates from one body rate.
  • set_va!(body_aero, va_distribution; pitch_rate_dist) takes it directly.
  • section_pitch_rate(velocity_leading, velocity_trailing, z_airf, chord),
    exported, builds one entry from a section's edge velocities.

section_pitch_rate reduces exactly to ω ⋅ y_airf under rigid motion
(v_TE − v_LE = ω × c·x_airf, and y × x = −z), so one expression covers both
cases and the sign convention — where an error flips damping into divergence — is
pinned in one place instead of being rediscovered by each caller.

It also closes a trap: the distributed set_va! never set omega, so reading it
there would have used a stale rate. Omitting the keyword now zeroes it.

Verification

  • The panel frame is right-handed and q > 0 is nose-up: a station 0.1c aft of
    the aero centre gains a positive z_airf velocity component, i.e. more
    incidence, matching the derivation.
  • dM · ω < 0 for both signs of ω — it damps rather than drives.
  • The summed increment matches the closed form πρVSc²/16 per rad/s
    (predicted 19.24 N·m at the test condition, measured 19.245).
  • Exactly zero at ω = 0, so default-off results are untouched.
  • Distributed path: an antisymmetric twist rate no rigid ω can produce, per-panel
    cm_dist increments matching flow_curvature_cm, opposite signs on the two
    half-wings, length mismatch throwing.
  • The relation itself is checked against measured section data, not just against
    the code. A rotating section is the A₁ = q c/(2 v_rel), A₂ = 0 case of
    cm_c/4 = (π/4)(A₂ − A₁); applying the same relation to NACA 4-digit mean
    lines gives −0.053 for the 2412 against a measured −0.047, −0.106 for the
    4412 against −0.093, and exactly zero for the symmetric 0012. The zero-lift
    angle is asserted from the same coefficients (−2.08° against a measured
    −2.1°), so a sign or factor error cannot hide in the moment alone.

Applied in both force paths — calc_forces! behind solve! and
calculate_results behind solve.

Caveats

  • Quasi-steady. Roughly a third of the full sectional pitch-damping moment; the
    apparent-mass part (−(π/2) q̂) is larger and belongs in the dynamics layer.
  • Second commit regenerates both default manifests: Arrow had become a direct
    dependency without reaching either, so seeding a fresh checkout from them left
    it unloadable. Unrelated to the physics change.

References

The relation this rests on, and the coefficient definitions used above:

MIT OpenCourseWare 16.01 Unified Engineering I–IV, Fall 2005 – Spring 2006,
Fluids Lecture 3 Notes: Thin-Airfoil Analysis Problem
(OCW).
A₀ = α − (1/π)∫₀^π (dZ/dx) dθ and Aₙ = (2/π)∫₀^π (dZ/dx) cos nθ dθ on p. 2;
c_ℓ = π(2A₀ + A₁) and c_m,c/4 = (π/4)(A₂ − A₁) on p. 3. The notes give
Anderson, Fundamentals of Aerodynamics §4.8 as the reading.

Only the substitution of the rotation-induced camber slope into those definitions
is done here; the integrals are in the description above and the resulting
relation is exercised against measured section data in the test suite.

For the apparent-mass term named in the caveats, which this PR does not add:

Theodorsen, T., General Theory of Aerodynamic Instability and the Mechanism of
Flutter
, NACA Report No. 496, 1935.
Section "Velocity potentials, forces, and moments of the noncirculatory flow",
pp. 292–294; the noncirculatory force and moment are eqs. (I) and (III) on
p. 294, with M_α taken about the rotation axis at ab from midchord and
lengths non-dimensionalised on the semichord b.
Scan: https://ntrs.nasa.gov/api/citations/19800006788/downloads/19800006788.pdf

Eq. (III) carries the π(1/8 + a²)b²α̈ and baπḧ terms, i.e. the added moment of
inertia about the rotation axis and the added-mass force acting at midchord —
the −(π/2) q̂ moment and the added-mass matrix discussed above both follow from
it. Note NTRS catalogues the scan under 1949, the year of the Annual Report
volume it was reprinted in; the report itself is 1935.

🤖 Generated with Claude Code

A section rotating about its own spanwise axis sees an incidence that varies
linearly along the chord. In thin airfoil theory that is the same boundary
condition as parabolic camber, giving A1 = q*c/(2V) and A2 = 0, hence
cm_c/4 = (pi/4)(A2 - A1) = -(pi/4) q_hat.

The lift half of the same effect was already exact: A0 + A1/2 collapses to the
effective incidence at three-quarter chord, which is where the inflow is
sampled, so no correction belongs there. Only the moment was missing, and one
control point per section cannot represent it because it is an A1 term rather
than an A0 shift.

What the moment responds to is the chordwise gradient of normal velocity across
a panel. For rigid motion that gradient is omega . y_airf, but a deforming wing
has a twist rate that varies along the span and no single body rate expresses
it. BodyAerodynamics therefore carries pitch_rate_dist, one rate per panel: the
rigid set_va! fills it by projection, the distributed set_va! takes it as a
keyword, and section_pitch_rate builds an entry from a section's edge
velocities. That helper reduces to omega . y_airf for rigid motion, so the sign
convention is pinned in one place rather than rediscovered by every caller.

Omitting the keyword zeroes the rates. The distributed set_va! never set omega,
so reading it there would have fed the moment a stale rate.

Off by default, applied in both force paths: calc_forces! behind solve! and
calculate_results behind solve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@1-Bart-1
1-Bart-1 force-pushed the feat/flow-curvature branch from 030ee89 to aebfd96 Compare August 17, 2026 09:41
1-Bart-1 and others added 2 commits August 17, 2026 11:46
Arrow became a direct dependency but never reached either default manifest, so
seeding a fresh checkout from them left the package unloadable. Regenerated both
with bin/install --update, which also carries the routine version bumps that had
accumulated since the last refresh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Regenerating the default manifests needs one resolve per supported Julia version,
but bin/install could only be pointed at a version through a stdin menu, and it
moved the juliaup default to get there — so refreshing the 1.11 manifest left the
shell on 1.11 afterwards.

--version X.Y and +X.Y select the channel for one run and only juliaup add it,
leaving the default alone. bin/update_default_manifests uses that to do both
versions in one command, matching the script in SymbolicAWEModels.jl.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/body_aerodynamics.jl 95.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

1-Bart-1 and others added 2 commits August 17, 2026 12:15
Documenter parses [flow_curvature_cm](@ref) as emphasis, so the link text
reaches cross-reference resolution as flow*curvature*cm and the docs build
fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
flow_curvature_cm rests on cm_c/4 = (pi/4)(A2 - A1), which nothing in the suite
pinned: the existing tests check the code matches that formula, not that the
formula is right, so a sign or factor error in it would pass everything and be
wrong by exactly that amount everywhere.

A rotating section is the A1 = q c / (2 v_rel), A2 = 0 case of the same
relation. Applying it instead to NACA 4-digit mean lines, where measured section
values exist, gives -0.053 for the 2412 against a measured -0.047 and -0.106 for
the 4412 against -0.093, both inside the accuracy thin airfoil theory is
expected to have, and exactly zero for the symmetric 0012. The zero-lift angle
is asserted from the same coefficients so an error cannot hide in the moment
alone.

Relation and coefficient definitions: MIT OCW 16.01 Unified Engineering, Fluids
Lecture 3 notes pp. 2-3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@1-Bart-1
1-Bart-1 merged commit 60c2651 into main Aug 17, 2026
9 checks passed
@1-Bart-1
1-Bart-1 deleted the feat/flow-curvature branch August 17, 2026 12:07
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