Skip to content

Release prep v2.3.0: restore the unmerged v2.2.0 content, land #167, changelog - #169

Merged
ocayon merged 16 commits into
developfrom
release/v2.3.0
Nov 4, 2026
Merged

ocayon merged 16 commits into
developfrom
release/v2.3.0

Conversation

@ocayon

@ocayon ocayon commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Prepares develop for the v2.3.0 release. It contains four things, each in its own commit:

  1. Merge of tag v2.2.0.
    • v2.2.0 was tagged on improve_plotting (c58337d), which was never merged into develop or main, so 9 released commits were missing.
    • That covers:
      • the Plotly plotting (src/VSM/plotly/, inflatable tubes, curved canopy, Cp force fields, with tests);
      • the body_axis fix in stability_derivatives._evaluate_with_angles;
      • the removal of a leftover plt.show() in trim_angle.py;
      • the 2.2.0 changelog entry;
      • CLAUDE.md and README updates;
      • LEI-V3 Surfplan export and Cp data;
      • SurfplanAdapter as a dependency (on PyPI, imported lazily).
    • Without this merge, v2.3.0 would silently drop fixes that v2.2.0 shipped.
    • It merges without conflicts.
  2. Merge of CasADi panel functions: polar tables as inputs, so one graph serves every deformed shape #167 (polar tables as CasADi inputs). CasADi panel functions: polar tables as inputs, so one graph serves every deformed shape #167 was merged into its stacked base after Quarter-chord force law as xp kernels + public API; allocation-free filament kernels #166 had already landed that branch, so 3cb7bd0 never reached develop. Land #167 on develop (polar tables as CasADi inputs) #168 brings in the same commit; merging both is harmless, so Land #167 on develop (polar tables as CasADi inputs) #168 can be merged or closed.
  3. The 2.3.0 changelog entry.
    • A "Changed (results)" section lists every default that changes results, with the option that restores the old behaviour where one exists.
    • It also covers removed options, the new CasADi APIs, fixes and performance.
  4. A skip for the test_masure.py tests when the model files are absent. The models in data/ml_models are git-ignored, so six tests failed on every clean checkout, including CI. test_masure_regression_requires_model_files also checked a path that does not exist (data/models), so it never ran; it now runs when the files are present. No source change, no effect on results.

Tests on this branch:

  • CI, without the model files: 213 passed, 11 skipped.
  • Local, with the model files: 220 passed, 4 skipped.

Merge order: this PR into develop, then the release PR develop → main, then tag v2.3.0 on the merge commit in main.

Written by Claude, reviewed by Oriol Cayon

jellepoland and others added 15 commits July 24, 2026 09:59
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an opt-in 'fancy' mode to interactive_plot that renders the physical
inflatable structure of a LEI kite: the leading-edge tube, the chordwise
strut tubes, and the curved single-skin canopy.

Passing surfplan_dir (a raw Surfplan export: a <name>.txt plus profiles/)
triggers a cached SurfplanAdapter conversion; the generated tube-diameter
tables and airfoil top-surfaces are then drawn on the wing. Omitting it
leaves the plain plot unchanged.

- src/VSM/plotly/surfplan_runner.py: run + cache the SurfplanAdapter pipeline
- src/VSM/plotly/tube_geometry.py: LE tube (diameter from leading_edge_tubes
  table) and profile-curved strut tubes (paired tip-to-tip with strut_tubes)
- src/VSM/plotly/canopy_geometry.py: loft airfoil upper contours into a canopy
- All geometry anchored on the drawn panels, so it is independent of the
  Surfplan export's coordinate frame
- interactive_plot gains surfplan_dir / is_with_canopy / is_with_tube_rings
- SurfplanAdapter added as a dependency; tests + tutorial step added

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Struts now start at the leading-edge tube's aft edge (buried half a tube
  depth in) instead of passing straight through it
- Leading-edge tube wraps around each wingtip and continues to the trailing
  edge of the outer panel (constant-diameter, tip-to-tip continuous)
- Twist-free parallel-transport ring framing (rings_along_centerline) so the
  swept surfaces do not pinch where the tube turns at the tips
- Solid (opaque) tubes so the leading-edge tube reads clearly over the canopy
- Split add_tube_surfaces into add_strut_surfaces / add_le_tube_surface so the
  leading-edge tube can be drawn last (on top)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- interactive_plot gains is_with_panels (default off in fancy mode); when off
  the panel outlines are hidden and drawn thin/blue when on
- Replace the per-panel force arrows over the canopy with a grid of equal,
  surface-normal vectors: one row per panel x 10 chordwise nodes placed at the
  true 5%-95% chord fractions (clear of the LE tube and trailing edge)
- Draw order: struts under the canopy, then canopy, then the vector grid, then
  the leading-edge tube last so it is never occluded
- Canopy recoloured grey; matte surface lighting
- Make the figure axis-range helper skip None/NaN gap separators

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the equal surface-normal vector grid with a physically-scaled loading:

- New VSM.plotly.cp_distributions: treat data/.../cpx_distributions as a Cp
  database keyed by AoA; select the closest available angle to the operating
  point and extract the upper (suction) surface |Cp|(x/c)
- Each panel's VSM force is distributed chordwise, weighted by |Cp| (even split
  without a Cp dir); the node forces of a panel sum back to that panel's force
- Vectors point normal to the local chord line (flat-panel up), constant per
  section, at the true 5%-95% chord fractions
- Normalise force->length so the largest panel force plots at the maximum chord
  length; modest fixed-size arrowheads
- interactive_plot gains cp_distributions_dir; add the V3 Cp/Cf data files and
  Cp-database tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ample

- Distribute each panel's VSM force over the chord weighted by the closest-AoA
  |Cp|(x/c); per-vector size anchored to a base of 10 nodes (extract the shared
  distributed_surface_vector_field into canopy_geometry)
- Cap the open tube ends (leading-edge + struts) so junctions read cleanly
- save_high_res_render: render on a square canvas (Plotly only renders a 3D scene
  undistorted when square), strip legend/axes/annotations, and auto-crop to the
  kite -> a clean, to-scale PNG
- Drop the forced cube aspectratio in the layout so the scene stays true-to-scale
- Add examples/TUDELFT_V3_KITE/fancy_interactive_plot.py running the pipeline and
  writing the high-res render; embed docs/plotly_render.png in the README

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bug plot, add changelog

- stability_derivatives._evaluate_with_angles now passes body_axis so baseline
  roll/pitch rates are not silently mapped to the z-axis
- trim_angle: remove leftover matplotlib debug plot/plt.show() in coarse sweep
- changelog: add 2.2.0 entry (rotational-inflow sign fix, body_rates/body_axis
  API, bridle 'd' key, solver/filament changes, plotly plotting)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmKZURQ7nvjtTzZXXqE6ze
On a deforming wing each panel's blended polar changes slightly every
coupled iteration. The CasADi residual and panel-force functions embedded
the tables as constants and were cached per table set, so a caller that
re-trims deformed shapes (AWETrim's CasadiTrim) rebuilt its graph every
iteration and could not afford to SX-expand it.

- _casadi_newton_function(table_inputs=False) and
  casadi_panel_force_function(table_inputs=False): with True the functions
  take cl_table, cd_table, cm_table, each (n_panels, n_alpha), as extra
  inputs and are cached per (panel count, alpha grid, settings), not per
  table values. The lookup is one 1-D parametric linear interpolant on the
  shared grid, mapped over panels: same nodes and clamping, so the outputs
  equal the embedded-table ones to round-off. Omitted tables default to
  NaN, never to a silently zero polar.
- Solver.casadi_polar_table_inputs() and casadi_stall_angle_inputs(): the
  current tables and stall-gate angles in the input layout.
- Linear polars on one shared alpha grid only (a parametric cubic spline
  refits per call, ~0.1 s); other cases raise a clear ValueError.

VSM's own loops keep the embedded-table functions and are unchanged: all
solve outputs are bit-identical to a801b5b (4 loop types, both
is_aoa_corrected settings, viscosity on/off). Expanded to SX, the table
function evaluates as fast as the embedded one (+2% at 135 panels).

Generated with Claude Code
CasADi panel functions: polar tables as inputs, so one graph serves every deformed shape
v2.2.0 was tagged on the improve_plotting branch (c58337d) and never merged
into develop or main. This brings in what that release shipped: the Plotly
plotting (inflatable tubes, curved canopy, Cp force fields), the body_axis
fix in the angle-derivative evaluation of stability_derivatives, the removal
of a leftover debug plot (plt.show) in trim_angle, the 2.2.0 changelog entry,
CLAUDE.md and README updates. Merges without conflicts.

Generated with Claude Code
#167 was merged into its stacked base feature/quarter-chord-xp-kernels after
#166 had already landed that branch on develop, so 3cb7bd0 never reached
develop (PR #168 brings it in on its own; merging both is harmless).

Generated with Claude Code
Lists the default-result changes of the consistent lifting-line coupling
(each with the option that restores the old behaviour where one exists), the
removed options, the new CasADi APIs, fixes and speedups, and notes that the
release includes the 2.2.0 content that had not been merged.

Generated with Claude Code
Copilot AI balanced review requested due to automatic review settings November 3, 2026 15:30
@ocayon ocayon mentioned this pull request Nov 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

The models in data/ml_models are git-ignored, so these six tests failed on
every clean checkout, including CI. Skip the module when they are missing.

test_masure_regression_requires_model_files checked data/models, a path that
does not exist, so it was always skipped. The module-level check replaces it
and that test now runs when the files are present.

No source change. Test bug, no effect on results.

Generated with Claude Code
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
5092 3943 77% 0% 🟢

New Files

File Coverage Status
tests/Solver/test_casadi_polar_table_inputs.py 100% 🟢
tests/plotting/test_tube_geometry.py 98% 🟢
TOTAL 99% 🟢

Modified Files

File Coverage Status
tests/AirfoilAerodynamics/test_masure.py 27% 🟢
TOTAL 27% 🟢

updated for commit: b7debde by action🐍

@ocayon
ocayon merged commit 7654085 into develop Nov 4, 2026
1 check passed
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.

3 participants