Polish the aeroelastic API for v5.1.0#222
Conversation
The aeroelastic naming pass leaned on several conventions that were only implicit in the codebase: component letters with singular or plural stems, names for angle component time derivatives, the stack, grid, and list collection prefixes, capitalized point-ID stems, and the rule that radians-based values must be marked in the name itself (Rad in camelCase portions, _rad on snake case names). Record them in AXES_POINTS_AND_FRAMES.md, ANGLE_VECTORS_AND_TRANSFORMATIONS.md, and CODE_STYLE.md so future code follows them deliberately. Also make "time step" and "step" interchangeable in prose and variable names, exempt compound units like N*m from operator spacing, and repoint both style docs' convention references from the superseded AXES_AND_COORDINATE_SYSTEMS.md to the current pair of vector docs.
Replace the nine per-wing state lists on AeroelasticUnsteadyProblem with two seeded structural time series, because the old current-state arrays and history lists recorded the same quantities twice and the remaining lists only fed diagnostics that are now deleted: the flap-cycle plotting machinery and the finite-difference inertial-moment and flap-point recording. Those inertial moments never fed the deformation ODE, whose inertial forcing is the analytic prescribed-motion function, and their recording meshed a throwaway undeformed reference Airplane every step, so deleting them is behavior-neutral and removes that per-step cost. Bump the serialization format version for the slot changes. Rename the structural surface to the naming conventions: the deformation angle series and the structural solve's locals and parameters carry component letters, Rad markers, and the Wcsp-to-Wcs sequence IDs, spring_constant_rad and damping_constant_rad declare their radians-based units in the public constructor, and generate_inertial_torque_function becomes generate_inertial_moment_function. Sweep the aeroelastic docstrings and comments so every mention of a vector-valued quantity or component names its axes, points, and rotation sequence, replacing references to the nonexistent SLEP and global panel frames with the first Airplane's geometry axes and the strip leading edge points. Adapt the tests, fixtures, and examples to the new surface, and add unit tests pinning that _record_structural_state records fresh state after the discard window and holds the previous state within it.
The plotting example now frames its result as the wing-tip twist history, names its output wing_tip_twist_spring_constant.png, and includes the pre-solve seed entry in the plotted series, so regenerate its expected output and repoint the docs page's image reference in the same change to keep the docs build coherent. Also correct the image's alt text, which misread the old filename's curve index of 16 as a spring constant of 16 and now describes the overlaid sweep.
Underscore-prefix AeroelasticUnsteadyProblem's six structural solve methods, which only the class itself calls: the mass matrix, wing deformation, spring moments, torsional spring moment, inertial moment function, and spring ODE routines. Land the change while the aeroelastic problem API is still unreleased, so retracting the methods from the public surface is non-breaking and the RTD page stops advertising coupling internals as user-facing API. Rewrite the class docstring's method listing, which named only the now-private methods, to cover the full public surface per the docstring convention for public subclasses of private parents, mirroring FreeFlightUnsteadyProblem's wording for the inherited entries and adding the aeroelastic properties.
Remove AeroelasticUnsteadyProblem's wing_movement property, which was hardcoded to the first airplane movement's first wing movement: the name promised a single primary wing movement that multi-wing configurations do not have, and the production call chain already passes each Wing's own movement explicitly, leaving the property's fallback role in the structural methods unreachable outside tests. Land the removal while the aeroelastic problem API is still unreleased, so it is non-breaking. Require the wing_movement parameter on the two structural methods that read prescribed flapping parameters, dropping the None default and fallback, so no trace of the first-wing assumption remains on the class. Rework the plotting example to compute its flap-angle overlay from module-level flap constants that also parameterize its wing movement constructions, so the prescribed motion is stated once.
Underscore-prefix seven of the nine SLEP slots on AeroelasticUnsteadyRingVortexLatticeMethodSolver: the index mapping, the five relative-position arrays, and the per-panel SLEP position stack are internal working state that no production code outside the solver reads. Keep moments_GP1_Slep public, since AeroelasticUnsteadyProblem's structural solve reads it as its aerodynamic forcing, and the free-flight precedent has the problem drive its solver through public surface. Present it in the class docstring as the structural coupling output, mirroring the free-flight solver's interface paragraph. Bump _FORMAT_VERSION from 17 to 18, since the renamed slots change the field names in saved solver states. The aeroelastic solver API is new in v5.1.0, so the renames are non-breaking ahead of the tag.
AeroelasticOperatingPointMovement was a pure marker: empty __slots__, no method overrides, existing only for naming consistency. Its constructor strictness forced users to mechanically re-wrap an identical OperatingPointMovement configuration. Delete it and loosen AeroelasticMovement to accept OperatingPointMovement directly, matching the free-flight family, whose marker classes were deleted under the same logic. AeroelasticMovement requires the concrete standard type, so a FreeFlightOperatingPointMovement is still rejected. Bump _FORMAT_VERSION from 18 to 19 for the serialization registry change.
An unmarked angle name implies degrees under the naming convention, and noting radians-based units in a docstring or comment alone is not enough, so the few radians-valued names that predate the rule are owed markers. Rename the sinusoid formula locals in the oscillation functions to b_rad and h_rad, matching the names their aeroelastic mirror in problems.py already uses, mark the airfoil geometry's mean camber line slope angles and chord angle with the convention's Rad camelCase marker and _rad suffix, and mark the aeroelastic plotting example's spring and damping sweep constants with _RAD to match the spring_constant_rad and damping_constant_rad parameters they feed. The renames are local to their files and change no behavior, no public API, and no plotted output, so no serialization format bump or expected-output regeneration is owed.
PyCharm flags four structural methods on AeroelasticUnsteadyProblem as candidates for static declaration and three locals as shadowing outer scope names, all in code this branch touches. The four methods (_extract_aero_moments, _build_deformation_vector, _generate_inertial_moment_function, and _spring_numerical_ode) read no instance state, so declare them static, following _build_next_operating_point in the same module. Every call site accesses them through an instance, which binds identically to a static method, so no call site changes. Rename _spring_numerical_ode's integration results to final_theta_rad and final_theta_derivative_rad so they no longer collide with the inner ODE function's state names, and rename the plotting example's function-local problem to solved_problem, out of the way of the module-level sweep variable of the same name.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #222 +/- ##
==========================================
- Coverage 93.79% 93.72% -0.07%
==========================================
Files 44 43 -1
Lines 8600 8506 -94
==========================================
- Hits 8066 7972 -94
Misses 534 534 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Polishes the unreleased aeroelastic API ahead of v5.1.0 without changing structural behavior.
Changes:
- Renames radians-based APIs and privatizes implementation details.
- Consolidates structural state into per-wing deformation time series.
- Removes redundant plotting infrastructure and marker classes while updating tests, examples, serialization, and conventions.
Reviewed changes
Copilot reviewed 30 out of 32 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
pterasoftware/problems.py |
Refines aeroelastic API and state handling. |
pterasoftware/aeroelastic_unsteady_ring_vortex_lattice_method.py |
Privatizes internal SLEP arrays. |
pterasoftware/_serialization.py |
Updates registry and format version. |
pterasoftware/_oscillation.py |
Marks radians-valued local names. |
pterasoftware/geometry/airfoil.py |
Clarifies radians-valued angle names. |
pterasoftware/movements/__init__.py |
Removes deleted marker export. |
pterasoftware/movements/aeroelastic_movement.py |
Accepts standard operating-point movements. |
pterasoftware/movements/aeroelastic_airplane_movement.py |
Clarifies deformation documentation. |
pterasoftware/movements/aeroelastic_wing_movement.py |
Clarifies deformation and moment terminology. |
pterasoftware/movements/aeroelastic_operating_point_movement.py |
Deletes redundant marker class. |
examples/aeroelastic_unsteady_first_order_plotting.py |
Plots the public deformation time series. |
examples/aeroelastic_unsteady_first_order_deformation.py |
Uses the polished API. |
examples/aeroelastic_unsteady_first_order_deformation_mixed_wings.py |
Uses the polished API. |
docs/examples_expected_output/aeroelastic_unsteady_first_order_plotting/wing_tip_twist_spring_constant.png |
Updates plotting example output. |
docs/website/examples/aeroelastic_unsteady_first_order_plotting.md |
References the renamed plot. |
docs/ANGLE_VECTORS_AND_TRANSFORMATIONS.md |
Documents angle-component naming. |
docs/AXES_POINTS_AND_FRAMES.md |
Documents components and collections. |
docs/CLASSES_AND_IMMUTABILITY.md |
Updates aeroelastic attributes. |
docs/CODE_STYLE.md |
Adds radians naming rules. |
docs/WRITING_STYLE.md |
Refines terminology rules. |
CLAUDE.md |
Removes deleted files from the tree. |
tests/integration/test_aeroelastic_unsteady_ring_vortex_lattice_method.py |
Updates physics regressions for the new state API. |
tests/unit/test_aeroelastic_movement.py |
Tests standard operating-point movements. |
tests/unit/test_aeroelastic_operating_point_movement.py |
Removes obsolete marker tests. |
tests/unit/test_aeroelastic_unsteady_problem.py |
Tests renamed methods and state recording. |
tests/unit/test_aeroelastic_unsteady_ring_vortex_lattice_method.py |
Updates private SLEP assertions. |
tests/unit/test_serialization.py |
Verifies renamed state serialization. |
tests/unit/test_slots.py |
Updates slot and property coverage. |
tests/unit/fixtures/problem_fixtures.py |
Uses renamed constructor parameters. |
tests/unit/fixtures/movement_fixtures.py |
Uses standard operating-point movements. |
tests/unit/fixtures/aeroelastic_operating_point_movement_fixtures.py |
Removes obsolete fixtures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
JonahJ27
left a comment
There was a problem hiding this comment.
Overall this looks great. My only notes are that the inertial moments while much cleaner, still could use being in their own function for clarity. Also wondering if M for moments is the standard over tau which I usually see for torque
|
@JonahJ27 Thanks for the review! I'll factor those out into a new function for clarity. I'm not wedded to either the |
Description
This PR gives the aeroelastic feature's public surface the same pre-tag polish the free-flight feature received in PR #206 and PR #207. It is a naming and visibility pass, not a behavior change: the structural spring-mass-damper model, its coupling to the solver, and every computed result are unchanged, and the two deformation examples' expected outputs needed no regeneration (the plotting example's was regenerated only because its plot was renamed and retitled). The changes fall into three groups: names brought to the documented conventions (most visibly, radians-valued names now declare their units), internal working state and helper methods made private, and a small amount of redundant or unused surface removed.
@JonahJ27: most of the touched code is your aeroelastic work, so this PR's review is meant to double as a walkthrough. Since re-adding public surface before the tag is additive and free, everything removed here is easy to bring back: if any removed method, property, or recorded quantity should stay, flag it in review and I will happily restore it.
Motivation
None of the aeroelastic problem, solver, or movement API has shipped in a release yet, so the window before the v5.1.0 tag is the only time this surface can be adjusted without breaking changes; after the tag, every public name becomes a compatibility commitment. The naming work continues the direction set by PR #190 and PR #198: after those units fixes, marking radians-based units in the names themselves, rather than only in docstrings, is the systematic guard against the same class of mismatch, and the convention docs now state the rules the renames follow. The visibility work keeps the deliberately public read surface small and matches the free-flight classes: what stays public is what a user or the coupled problem genuinely reads (the per-wing deformation time series, the structural constants, and the solver's per-panel moments about the strip leading edge points), while the internals stay free to evolve.
Relevant Issues
None.
Changes
AeroelasticUnsteadyProblem's per-wing structural state: the nine*_per_winglists are now two seeded per-wing time series, the publiclistDeformationAnglesYRad_Wcsp_to_Wcs_ixyzand the private_listDeformationAnglesDerivativeYRad_Wcsp_to_Wcs_ixyz. The old lists were state/history pairs recording the same quantities twice, plus feeders for the plotting machinery removed below, so the two series subsume them. The record-versus-hold behavior understep_discardsis unchanged and is now pinned by new unit tests of_record_structural_state.problems.py:plot_flap_cycle_curves, theplot_flap_cycleparameter,calculate_wing_panel_accelerations, the finite-difference inertial-moment recording, and the module-level matplotlib import. The finite-difference moments never fed the deformation ODE, whose inertial forcing is the analytic prescribed-motion function, so this is behavior-neutral, and it also stops the meshing of a throwaway undeformed reference Airplane every time step, a cost previously paid even with plotting off. The supported plotting pattern (read the public time series and plot user-side) lives inexamples/aeroelastic_unsteady_first_order_plotting.py.AeroelasticUnsteadyProblem(_calculate_mass_matrix,_calculate_wing_deformation,_calculate_spring_moments,_calculate_torsional_spring_moment,_generate_inertial_moment_function, and_spring_numerical_ode); nothing outside the class called them.generate_inertial_torque_functionis also renamed to_generate_inertial_moment_functionto match the moment vocabulary used everywhere else.wing_movementproperty, which was hardcoded toairplane_movements[0].wing_movements[0]and therefore arbitrary for any multi-wing configuration (the shipped examples carry three WingMovements). The two structural methods that read prescribed flapping parameters now take their AeroelasticWingMovement explicitly, and the plotting example computes its flap-angle overlay from the same module-level constants that parameterize its wing movement constructions.AeroelasticUnsteadyRingVortexLatticeMethodSolver.moments_GP1_Slepstays public as the structural coupling output thatAeroelasticUnsteadyProblemreads as its aerodynamic forcing, matching howFreeFlightUnsteadyProblemdrives its solver through public surface, and the solver's class docstring now presents it that way.AeroelasticOperatingPointMovementand letAeroelasticMovementaccept a standardOperatingPointMovement, mirroring PR Delete free-flight movement markers #207's free-flight marker deletions: the class had empty__slots__and no overrides, so it only forced users to re-wrap an identical configuration under a different name. AFreeFlightOperatingPointMovementis still rejected.spring_constant_radanddamping_constant_radon the constructor, properties, and slots; the deformation state and structural solve names carryRadper the angle vector convention; and the last unmarked radians-valued names in_oscillation.py(b_radandh_rad) andgeometry/airfoil.py(thetaSlopeRad_Ax_to_MCLandchord_angle_rad) follow the same rule.ANGLE_VECTORS_AND_TRANSFORMATIONS.md(angle vector components, time derivative markers, and theRadrule),AXES_POINTS_AND_FRAMES.md(component letters, point ID capitalization, and thestack,grid, andlistcollection prefixes),CODE_STYLE.md(the snake case_radrule), andWRITING_STYLE.md.CLASSES_AND_IMMUTABILITY.md's tables track the new attribute set.examples/aeroelastic_unsteady_first_order_plotting.pyaround the public time series and regenerate its expected output (nowwing_tip_twist_spring_constant.png, with the pre-solve seed entry plotted), repointingdocs/website/examples/aeroelastic_unsteady_first_order_plotting.mdin the same pass. All three aeroelastic examples now construct anOperatingPointMovementdirectly._FORMAT_VERSIONfrom 16 to 19 across the slot renames and the serialization registry change; no released build ever sees the intermediate integers.Dependency Updates
None.
Change Magnitude
Moderate: Medium-sized change that adds or modifies a feature without large-scale impact.
Checklist (check each item when completed or not applicable)
mainand is up to date with the upstreammainbranch.--in-place --black). See the style guide for type hints and docstrings for more details.pterasoftwarepackage use type hints. See the style guide for type hints and docstrings for more details.testspackage.testspackage.ascii-only,black,codespell,docformatter,isort, andpre-commit-hooksGitHub actions.mypyGitHub action.testsGitHub actions.