[BUG] Fix aeroelastic strip ordering#190
Conversation
The previous construction recorded one index per wing cross section and only advanced the running panel count by each section's spanwise panel count, which assumed the solver's flat panel stack was grouped into spanwise strips with a single chordwise row. The stack is actually ordered chord-major within each wing, so the searchsorted lookup matched most panels to the wrong strip leading edge points, and the moments taken about those points were wrong. Record one index per panel that points directly at the panel in the first chordwise row at the same wing and spanwise position. This also lets the transform gather the leading edge points with a single fancy index instead of the searchsorted lookup.
A mirror-meshed Wing's panel grid runs tip to root spanwise, while its wing_cross_sections list runs root to tip. The structural solve assumed every wing's spanwise panel index ran root to tip, so on the reflected half of a type-5 symmetric wing, each strip's ODE was forced by its own aerodynamic moments but given the chord, strip width, and flapping moment arm of the strip mirrored across the semispan, and the resulting twist rows were applied to the WingCrossSections in reversed spanwise order. A symmetric flapping configuration therefore deformed asymmetrically. Flip the spanwise axes of the per-panel mass and moment arrays into root-to-tip strip order before the structural solve, and map the spanwise index when reading panel geometry, so the solve and the movement classes that consume its output share one ordering for every wing.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #190 +/- ##
=======================================
Coverage 92.15% 92.15%
=======================================
Files 44 44
Lines 7822 7829 +7
=======================================
+ Hits 7208 7215 +7
Misses 614 614 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Hey @JonahJ27! While verifying these two fixes, I think I found a third problem in The unit chain I see is:
I don't think this can be fixed by re-documenting units alone, since the aero moments and the inertias are pinned to SI. The fix that matches the docstrings as written is to keep the structural model in radians and convert at the boundaries. Heads up that if this is real, fixing it could change results substantially so we may need to retune the placeholder spring and damping constants in the examples/tests. |
|
Hi Cam, Great catches here. I'm quite confident the symmetry bugs you caught were introduced in my potentially too hasty transition to running deformation on all of the wings. The numbers actually look much closer to what I had before the change (slightly different because of that other bug fix I put in in the :1 vs :2 indexing, but I digress). So your changes generally feel correct. As for the degrees and radians stuff, I've implemented a fix for it, the notable part of it is that for the inertial and spring part, the amplitude we're using was also not getting converted out of degrees, so we convert and convert back as you suggested if I understand your point correctly. This leads to essentially the same outcome with the exception of aero torque which means that the outcome is exactly the same as before if I set aero scaling to 1/57.3. Alternatively, I can crank up the damping parameters significantly to damp out the aero moments, but that also requires changing the wing density significantly and makes the spring constant not matter unless it's very large. I would love a chance to chat about what is the best potential solution to this, and what is causing this aero moment to dominate the scale so much |
|
I also can't push my changes to this branch so I'm making a new branch |
|
I've made some default parameter updates so that everything works without aero scaling |
Description
This pull request fixes two indexing errors in the structural side of the aeroelastic UVLM, both caused by incorrect assumptions about how the solver's panels are ordered relative to spanwise strips. The first fix rebuilds the strip leading edge point (SLEP) bookkeeping in
AeroelasticUnsteadyRingVortexLatticeMethodSolver, which assumed the flat panel stack was grouped into one spanwise strip perWingCrossSectionwith a single chordwise row, when the stack is actually ordered chord-major within each wing. The second fix teaches the structural solve inAeroelasticUnsteadyProblemthat a mirror-meshedWing's panel grid runs tip to root spanwise, while itswing_cross_sectionslist, the structural solve, and the movement classes that consume the solve's output all run root to tip. Both fixes are internal to the aeroelastic coupling: no public interfaces change, and the purely aerodynamic solvers and the free flight coupling are unaffected.Motivation
The SLEP misindexing meant that every panel behind the first chordwise row was matched to the wrong strip's leading edge point, so the per-strip aerodynamic moments that force each strip's torsional spring-mass-damper model were taken about the wrong points. The mirror-mesh ordering bug affected
Wings meshed as reflections (those withmirror_onlyset toTrue, which covers symmetry types 2 and 3 as well as the reflected half thatAirplane.process_wing_symmetry()produces when handling a type 5 symmetricWing): each strip's deflection ODE was forced by its own aerodynamic moments but given the chord, strip width, and flapping moment arm of the strip mirrored across the semispan, and the resulting twist rows were applied to theWingCrossSections in reversed spanwise order. The visible symptom was that a geometrically and kinematically symmetric flapping configuration deformed asymmetrically. Both are deterministic logic errors rather than numerical artifacts, so no amount of mesh or time step refinement could have converged them away.Relevant Issues
None.
Changes
AeroelasticUnsteadyRingVortexLatticeMethodSolver.__init__(), rebuilt theslep_point_indicesarray to hold one entry per panel: the flat index of the panel in the first chordwise row at the same wing and spanwise position, whose front-left point is the strip's leading edge point. The old construction recorded one index perWingCrossSectionand advanced the running panel count by spanwise panel counts alone, which assumed a spanwise-strip grouping that does not match the chord-major panel stack.AeroelasticUnsteadyRingVortexLatticeMethodSolver._update_bound_vortex_positions_relative_to_slep_points(), replaced thenp.searchsorted()lookup and per-panel list comprehension with a single fancy-index gather through the per-panelslep_point_indices, which is both correct for the chord-major order and simpler.AeroelasticUnsteadyProblem.calculate_wing_deformation(), flipped the spanwise axes of the per-panelmass_matrix,aeroMoments_GP1_Slep, andinertial_momentsarrays into root-to-tip strip order before the structural solve when theWingis mirror-meshed.AeroelasticUnsteadyProblem.calculate_spring_moments(), mapped the root-to-tip spanwise section index to the panel grid's tip-to-root order when reading the strip width fromfrontLeg_Gfor mirror-meshedWings._apply_moment_updates()andcalculate_spring_moments()to state that the deformation, angular velocity, mass, and moment arrays use root-to-tip spanwise order, and updated the block comments around the SLEP construction to describe the chord-major panel stack.Dependency Updates
None.
Change Magnitude
Minor: Small change such as a bug fix, small enhancement, or documentation update.
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.