Repository navigation
Conversation
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
The quarter-chord flow that sets the force directions (TAT3) held the other panels' bound segments evaluated on the bound line itself. On a curved or swept line that self-induction is logarithmically singular (Li, Gaunaa, Pirrung, Ramos-Garcia & Horcas 2020, "LL-P&S"), and because the on-blade induced drag is rho*Gamma*(w cos a + u sin a) with w only ~1 deg of induced angle, the chordwise u it produces moved the V3 drag by 10% and kept moving it with the panel count: on-blade over Trefftz 0.93 / 0.90 / 0.86 at 20 / 50 / 150 panels. Leaving the term out is worse (swept wings collapse, because the streamwise legs carry the opposite singularity), and reusing Li's 3/4-chord difference at the quarter chord breaks straight wings here. Replace the term by the difference between the actual vortex system and the same wing unrolled onto each panel's tangent line, with the bound vorticity and the leg starting points of every ring spread along the chord with the thin-airfoil distribution sqrt((c-x)/x). The quarter-chord velocity is then Prandtl's downwash of the unrolled wing plus a bracket that is identically zero on straight wings, finite on curved ones (the distribution fixes the cut-off at 0.15 c, no tunable length) and mesh-independent. Same mechanism as the effective-lifting-line / jointed-vortex method of Reid & Hunsaker (2020), whose two empirical lengths it removes; discrete counterpart of the inner solution of curved lifting-line theory (Guermond 1990). On-blade over Trefftz induced drag, inviscid: straight 1.000 (unchanged); arc R=4c 0.999 at 40, 80 and 160 panels; V3 1.007 / 1.008 / 1.010; swept 30 deg 0.97 -> 0.99; swept-anhedral elliptic wing of Gaunaa et al. 1.01. V3 viscous polars: lift unchanged, CD +0.001 at 5 deg, +0.006 at 10 deg, +0.011 at 13 deg, onto the RANS values. Cost: one numba kernel evaluated once per solve (about 1 s at 80 panels). Docs: Solver.md section on the consistent coupling, figures 03 (regenerated), 08 (mechanism and fix) and 09 (V3 polars) with README entries. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…und-vortex regularisation docs/validation/curved_bound_vortex_validation.py reproduces every table of the report from the committed solver: on-blade over Trefftz induced drag against panel count for a straight wing, skewed ribs, a 30 deg swept wing, a circular arc, the TORQUE 2026 swept-anhedral elliptic wing and the V3, for the regularisation and for the alternatives that were tried and rejected (trailed system only, bound segments on the line as on develop before, the literal Li et al. 2020 recipe, the Reid & Hunsaker 2020 effective-line construction with its joint and blending parameters), the arc mid-span self-induction (polyline vs chordwise-spread sheet), the V3 viscous polars, and figures 08 and 09. Full run 193 s; results in the JSON next to it. docs/validation/curved_bound_vortex_report.tex/.pdf: problem statement, cause, literature (Li 2018/2020, Gaunaa 2026 and its online appendix, Reid & Hunsaker, Guermond 1990, core methods), the formulation, the verification tables and the V3 polars against RANS and the wind tunnel, plus the two points where the code still deviates from the published Li/Gaunaa prescription. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… the regularisation in place docs/validation/leg_direction_study.py repeats the September leg-direction comparison with the curved bound-vortex regularisation (f43bcdb) instead of the singular bound-on-line term: on-blade over Trefftz induced drag on the arc, the swept-anhedral elliptic wing, the inviscid V3 and a kinked 30 deg swept wing, with the attached-trailed force on and off, and the V3 viscous polars against RANS, for rib legs and for span-perpendicular (CP1) legs. Results in leg_direction_study.json (149 s). Outcome: the rib legs stay. Perpendicular legs cannot be built on the kinked planform (adjacent perpendiculars cross, NaN), lower the V3 inviscid lift by 6% and the agreement with RANS (mean |dCL| 0.031 against 0.020), and with the attached-trailed force sit 2.5-4% above the Trefftz plane on the swept V3 and elliptic lines, the same excess the TORQUE 2026 appendix shows on the authors' swept wings. Rib legs are within 1.5% on every curved case. No solver change. Report: new Section 4.3 with the table, status item 2 and the open items updated; PDF rebuilt (10 pages). Figures README entry 07 carries the new numbers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… discrepancy 118e91d stated that the TORQUE 2026 appendix shows the same 1-6% excess of on-blade over Trefftz induced drag that perpendicular legs give here. The sign is the opposite: in Gaunaa, Li & Pirrung (2026) Table 2 and the appendix the on-blade induced drag of LL-Gaunaa is 1-5% below the Trefftz plane on the swept wings (e_Osw,Blade above e_Osw,Trefftz), and their VLM reference is 3% below as well. The report now states this, quotes the paper's own wording that the leg direction is a modelling choice not fixed by theory, and notes that the paper runs the legs up to the trailing edge while the perpendicular legs tested here have a fixed length. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ged with a vortex-lattice referee BodyAerodynamics(..., leg_direction="rib" | "streamwise" | "perpendicular"), also on instantiate(). "rib" (default, unchanged behaviour) keeps the legs along the interpolated input sections. "perpendicular" is the TORQUE 2026 recipe: legs along the CP1 chord direction, perpendicular to the quarter-chord line, up to the trailing-edge curve; the line tangent is averaged over one leg length so the legs fan out instead of crossing at a planform kink (no free parameter), the leg ends at the closest point of the trailing-edge curve (extended at its ends for skewed tips), and the control point moves between the panel's own legs (without that, kinked wings diverge). "streamwise" projects the apparent velocity onto the surface and rebuilds the legs whenever va is set. utils.perpendicular_leg_end_points, Panel.set_leg_end_points. Legs that still cross raise ValueError. Referee: docs/validation/vlm_referee.py runs the AeroSandbox VLM (flat-plate sections) on straight, yawed, kinked-swept, arc, swept-anhedral elliptic wings and the inviscid V3, with the Trefftz drag of the VLM circulation (its near-field drag is low on non-planar wings). Rib and streamwise legs reproduce the VLM lift within 1% on all planar and curved wings (streamwise 2% low on the arc); the perpendicular legs lose 9% on the kinked wing and 8% on the V3, where they also cross at the tips above 80 panels. On the V3 against RANS the streamwise legs give the closest polars (drag within 0.3% up to 10 deg). The rib legs stay the default; the earlier fixed-length perpendicular test (118e91d) is superseded. Docs: report Section 4.3 rewritten with the three constructions, the referee tables and figures 10 (geometry: legs, aerodynamic centres, control points, VLM lattice) and 11 (referee); status item 2 and open items updated; docs/Solver.md and figures README. Tests: tests/BodyAerodynamics/ test_leg_direction.py (11 tests: equality with ribs where ribs are perpendicular or streamwise, skewed ribs give the straight wing, kinked wing builds and converges, crossing raises, legs follow the inflow). Full suite 181 passed, 5 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
BodyAerodynamics(leg_direction="streamwise") becomes the default (was "rib"). The legs run along the apparent velocity projected onto the surface, up to the trailing-edge curve, and are rebuilt whenever va is set; they depend only on the quarter-chord line, the trailing edge and the flow, not on how the input sections were drawn, follow the inflow in sideslip, and give the closest V3 polars to RANS (drag within 0.3% up to 10 deg, lift slope equal to the RANS one). Known cost, from the AeroSandbox referee: 1-3% less lift than a lifting surface on the nearly vertical tips of an arc wing at 4-15 deg (rib legs: -0.2 to +1.6%), with the induced drag closer; up to 7% less lift at high angle of attack on the thesis curved-wing case. The change is physical: the vortex system differs where the ribs are not aligned with the flow (kite tips, sideslip); identical results on wings whose ribs are drawn along the flow. An inflow without a mean direction (pure rotation about the centroid) has no streamwise legs: the rib legs are used for that inflow and a warning is logged (Panel.reset_legs_to_ribs). After a geometry rebuild (rotate, update_from_points) the legs follow the stored inflow distribution. Tests that verify the thesis vortex system (tests/utils.py, the create_geometry_general oracle, the curved-wing and V3 verification cases) and the regularisation tests (chordwise legs isolate the bound-vortex term) now pass leg_direction="rib" explicitly; make_pr_figures.py and the regularisation validation script likewise, so figures 01-09 and the report's Sections 2-4 stay reproducible. New test: fallback for pure rotation. Report (decision paragraph, status, open items), Solver.md and the figures README state the new default and its cost. Suite: 182 passed, 5 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Reverts the default of def20bb. The code's main use is trim finding with an inflow that varies along the span (body rates, distributed va), where the streamwise construction can only use the mean inflow direction and is rebuilt at every inflow; the rib legs give a fixed vortex system of the same accuracy (better on arc-shaped tips against the VLM). The streamwise and perpendicular constructions, the referee, the tests and the figures are unchanged; the report, Solver.md and the figures README state the reasoning and the mean-direction limitation. Suite: 182 passed, 5 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d validation docs/Aerodynamic_model.pdf held chapter 4 of the 2022 MSc thesis, with no source in the repository and sections left empty. It is replaced by an 18-page document whose source is docs/aerodynamic_model/aerodynamic_model.tex (latexmk; the compiled file is copied to docs/Aerodynamic_model.pdf). Contents: scope and assumptions; geometry and the CP1 panel frame; the vortex system (filaments, Biot-Savart, cores, influence matrices, wake, the three attached-trailed leg constructions); the inner-outer coupling (TAT1-3, Gamma = 1/2 |V_inner| c Cl, quarter-chord directions, the curved bound-vortex regularisation, the attached-trailed force, the spanwise viscous correction, artificial viscosity, the LLT variant); solver, inflow, outputs, Trefftz drag and bridle lines; validation (horseshoe and elliptic analytical cases, Trefftz consistency, the AeroSandbox VLM referee on planar, swept, arc, elliptic and V3 wings, the V3 against RANS and the wind tunnel, mesh convergence, the regression cases); limits; a table of conventions. Every figure names the script that generates it. New figures 12 (classical wings against Prandtl and the VLM; the LLT loses its Trefftz consistency on a curved quarter-chord line, the VSM does not) and 13 (mesh convergence), from docs/validation/aerodynamic_model_figures.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ror) 1105122 (Copilot Autofix, "Refactor ratio and gate condition") replaced five lines with one: it kept the new ratio expression but deleted the crossed_gate assignment and the opening `if not finite(trial) or (` with its condition, leaving a bare `):` at Solver.py:1447. Every `import VSM` on main raised SyntaxError: unmatched ')', so every fresh install of a package that depends on VSM@main (AWETrim) failed. Restores the condition and keeps the autofix's intended change: a trial with exactly zero residual now has ratio = inf (accepted) instead of 0 (rejected). (cherry picked from commit beb0a4f)
…metry The quarter-chord correction (assemble_curved_bound_correction_AIC) depends on the panel geometry only: the wake terms cancel between the actual and the unrolled systems and the inflow speed does not change the result (bit identical on the V3 at 10, 20 and 40 m/s). It costs about 0.5 s at 50 panels and was rebuilt on every solve, which multiplied in a coupled aerostructural trim that solves one deformed geometry hundreds of times (231 s against 60 s for one LEI-V3 wireframe case with the old force directions). It is now cached on a hash of the arrays the kernel reads (evaluation and bound points, leg ends, chord directions, chords) plus the chord fractions, so a rebuild, a rotation, a moved point or a changed leg construction invalidates it; a solve on an unchanged geometry takes about 0.1 s at 54 panels. Results are unchanged. Test: one kernel evaluation for two inflows on the same panels, identical results to a fresh body, and a recomputation after a rotation. Suite: 183 passed, 5 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tion A trim that rotates the body for every residual evaluation (AWETrim's quasi-steady trim) rebuilds the panels each time, so the per-geometry cache of 2644b5c never hit: profiling one LEI-V3 coupled case showed the kernel on all 280 solves, 135 s of 222 s. The cache now stores the evaluation, bound and leg-end points, the chord directions and chords of the computed geometry; when the current panels are that geometry up to a rigid rotation and translation (Kabsch fit, residual below 1e-9 of the size), the stored matrix is rotated instead of rebuilt, since its entries are velocity vectors that rotate with the body. A different shape recomputes. Test: one kernel evaluation for a rotated body, the same lift and drag as a body built in the rotated position, and a recomputation after a trailing-edge point is moved. Suite: 183 passed, 5 skipped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd the model document docs/validation/unrolling_figure.py draws, for the arc wing, the kinked swept wing and the V3, the straight reference wing that the curved bound-vortex regularisation builds on each evaluation panel's own tangent (one per panel, nodes at their arc-length distances, legs along that panel's chord direction), and the distance between actual and unrolled nodes against the distance from the panel: the near field coincides and cancels in the difference, the far field is the curvature effect. Figure 14 in docs/figures, placed after eq. 6 of the regularisation report and in Section 5.3 of the aerodynamic model document; both PDFs rebuilt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
docs/validation/chord_spread_figure.py draws the 24 thin-airfoil strips on real and unrolled panels of the arc wing, the chordwise velocity one neighbouring segment induces at the quarter-chord point as a filament and as a sheet (equal beyond a chord, finite within it only for the sheet, levelling at the 0.15 c cut-off), and the running sum of the neighbours from far to near at 40 to 320 panels (filaments keep rising, sheets settle). Figure 15 in docs/figures, placed after the spreading paragraph of the regularisation report and in Section 5.3 of the aerodynamic model document; both PDFs rebuilt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e printing New Section 4.2 'Reading of the formulation': the quarter-chord construction is the same handover rule as TAT1 at the three-quarter chord (3D minus what the 2D section already contains, with the unrolled wing as the section's straight continuation); the chordwise sheet is the vorticity the inner model is made of, with a table showing that the three-quarter chord sums converge and need no sheet while the quarter-chord sums do not; the two sheet terms are the same panel in two positions. 'Other approaches' gains the per-panel segment-minus-infinite-line subtraction, tested and divergent like one over the panel width squared. Table 4's perpendicular-leg rows now use the current construction (the earlier rows were the superseded fixed-length legs). Open items gain the body-rate direction velocity (effective torsional rate, Li, Gaunaa and Pirrung 2026 preprint). Abstract mentions the leg referee; title block and date updated; 17 pages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…othesised LL-Gaunaa term Report Section 4.2: derivation of the velocity two line vortices meeting at a kink induce on each other (Gamma (1 - cos theta) / (4 pi r sin theta), unbounded at the kink), its sum over a curved line (the logarithm of the span over the panel width) and the same sum for chord-spread sheets (the logarithm of the span over 0.15 c, mesh-independent), with figure 16 from docs/validation/kink_figure.py. Report Section 3.1: the form that reproduces the published behaviour of LL-Gaunaa, curved-minus-straight bound segments as single filaments at the three-quarter-chord control point reused at the quarter chord, is now implemented in the validation script (--hypothesis) and tabulated: it is mesh-independent and within 1-2 % of the Trefftz plane with the paper's perpendicular legs, and fails with rib legs on the V3 (0.81 -> 0.74) and the kinked wing, because skewed legs carry their own logarithm that a bound-only difference cannot see. Open item and status updated accordingly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…p loading Replace the flat-plate thin-airfoil strip weights by the NeuralFoil loading (gamma = ue_upper - ue_lower) of the V3 centre section at 5, 10 and 15 deg and of a NACA 4412. The effective cut-off moves from 0.16 c to 0.13 c and the centroid aft of the quarter chord; the arc wing changes by at most 0.3 % and the V3 induced drag by 0.5-1.5 %, within the referee's own uncertainty. The flat-plate weights are kept (solution-independent, cached per shape). Script docs/validation/strip_weight_sensitivity.py, report Section 4.2 (Table tab:strips). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hysics Narrative: Prandtl's straight wing as the exact baseline and why; curvature makes two line vortices at an angle induce an unbounded velocity on each other, hence the logarithm and the mesh drift; Li and Gaunaa avoid the quarter-chord point and assume the velocity constant along the chord and the legs perpendicular; a section is a chordwise sheet and two sheets at an angle see a finite velocity; the correction is the real wing as sheets minus the wing straightened at the section as sheets, added to Prandtl, so that curvature is isolated and the section's own field never enters; results against the Trefftz plane, a vortex lattice and RANS. Alternatives tested, strip-loading sensitivity, the leg study in detail and the implementation status move to appendices. 16 pages (was 19). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ularisation Feature/curved bound vortex regularisation
The induced-velocity kernels carried vectors as length-3 arrays; in numba every temporary (np.cross, r1 - r0, np.zeros(3)) is a heap allocation, and those allocations were ~95% of the cost: ~1.1 us per filament evaluation. They now carry 3-tuples, which numba keeps on the stack (~15-19 ns). Formulas, branch structure and summation order are unchanged, so the matrices still match the Filament.py reference to round-off (the equivalence tests at rtol 1e-12 pass). error_model="numpy" keeps NumPy's inf/nan semantics for zero denominators instead of numba's scalar ZeroDivisionError, so degenerate geometry behaves as before. V3 kite, 36 panels: AIC 7.3 -> 0.10 ms; casadi_newton solve 44 -> 24 ms. Affects assemble_AIC_matrices, assemble_curved_bound_correction_AIC and induced_velocity_at_points. Numerical, not physical; outputs unchanged. Generated with Claude Code
The section force law moves into VSM.core.panel_kernels, pure functions over an xp namespace (numpy or casadi), so CasADi callers (AWETrim's CasADi trim) use VSM's formula instead of restating it. compute_results calls the same kernels for its per-panel force, so the formula lives once. - BodyAerodynamics.compute_quarter_chord_AIC_matrices(core_radius_fraction, va_norm_array, va_unit_array): public quarter-chord induction, AIC_LLT + the cached curved bound-vortex correction. update_effective_angle_of_ attack_if_VSM now uses it (one source). - panel_kernels: relative_flow, quarter_chord_velocity, direction_angle, section_force_directions, section_force_magnitudes, section_force_vectors, panel_forces, panel_moment_local, attached_trailed_forces, row helpers. compute_results and compute_attached_trailed_vortex_forces call them. - Solver.casadi_panel_force_function(): CasADi function (v_rel, v_qc, axes, chord, width, rho) -> per-panel force, local moment, alpha, alpha_dir, umag, cl, cd, cm, on the same polar lookups as the casadi_newton residual (factored into _casadi_polar_lookups; the residual function is unchanged). Refactor plus API: no physics change. Every numeric solve output matches VSM 1201f6f to <= 1.5e-14 relative for is_aoa_corrected True and False on a straight, a swept, an arc wing and the LEI V3 kite (frozen reference in tests/BodyAerodynamics/data, written with 1201f6f). CasADi kernels equal the NumPy ones to 1e-12; a CasADi graph with the induction matrices as parameters reproduces compute_results panel forces to 2e-16. Generated with Claude Code
…dual calls - compute_trefftz_plane_induced_drag: the O(n^2) per-panel Python loop with np.cross becomes one vectorised evaluation (1.3 -> 0.2 ms at 36 panels). It is a far-wake diagnostic computed on every solve; output unchanged. - Wing.compute_projected_area: vectorised over the strips (1.3 -> 0.1 ms). Also stops normalising the caller's z_plane_vector in place. - gamma_loop_casadi_newton: the inputs that are constant within a solve are converted to CasADi matrices once, and the loop calls a cached variant of the residual function with only the six outputs it reads (same graph). ~185 -> ~77 us per residual evaluation. Numerical, not physical. Sums are reordered, so outputs move at round-off only: every solve output still matches 1201f6f to <= 1.5e-14 relative. V3, 36 panels, casadi_newton: ~24 -> ~17 ms per solve. Generated with Claude Code
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
Quarter-chord force law as xp kernels + public API; allocation-free filament kernels
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
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
Land #167 on develop (polar tables as CasADi inputs)
Contributor
There was a problem hiding this comment.
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
Release prep v2.3.0: restore the unmerged v2.2.0 content, land #167, changelog
☂️ Python Coverage
Overall Coverage
New Files
Modified Files
|
Name the chordwise thin-airfoil loading of the curved bound-vortex correction, a new modelling assumption. Add the anderson_max_iterations default, the new Panel leg methods and the SurfplanAdapter dependency, and set the release date. Documentation only, no effect on results. Generated with Claude Code
docs(changelog): complete the 2.3.0 entry
…elocity Say that the circulation uses the span-perpendicular effective velocity, including induction, and state the old formula in the same terms. Documentation only, no effect on results. Generated with Claude Code
docs(changelog): describe the circulation velocity as the effective velocity
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.
Release PR for v2.3.0. Merge it after #172, the last changelog wording change on
develop.Default results change
Forces, moments and coefficients computed with the defaults differ from 2.2.0, most on swept and curved wings such as kites. The lifting-line coupling now follows the consistent formulation of Gaunaa, Li & Pirrung (TORQUE 2026):
is_aoa_corrected=True);is_with_attached_trailed_vortex_force=True);On-blade induced drag now matches the Trefftz plane within about 1 % on arc, swept and kite geometries, independently of the panel count.
changelog.mdlists each change and the option that restores the old behaviour, where one exists. The formulation and validation are indocs/aerodynamic_modelanddocs/validation.Breaking changes
Solveroptions that were never read, and three Simonetgamma_loop_typevalues that already raisedImportError. An unknowngamma_loop_typenow raisesValueError.Solver.compute_aerodynamic_quantitiesno longer returnsUmagw.anderson_fallback_to_base=Truerestores it).The version is a minor bump, following the precedent of 2.1.0, which also changed results through a default.
Also in this release
body_axisfix instability_derivativesand theplt.show()removal intrim_angle.v2.2.0was tagged on a side branch and never reachedmain.casadi_newtonloop;VSM.core.panel_kernels;compute_quarter_chord_AIC_matrices;casadi_panel_force_function;SurfplanAdapter.casadi_newtonsolve takes about 17 ms, down from about 50 ms.Validation
release/v2.3.0, without the git-ignoreddata/ml_modelsfiles: 213 passed, 11 skipped. Thetest_masure.pytests are among the skipped ones, so CI does not exercise them.After merging
git tag v2.3.0 <merge-sha> && git push origin v2.3.0. The version comes fromsetuptools_scm.Written by Claude, reviewed by Oriol Cayon