Conversation
theta_idxs and delta_idxs run over the unrefined sections of all wings in order, the order calc_forces! fills moment_unrefined_dist in. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1-Bort-1
left a comment
There was a problem hiding this comment.
Independent review (advisory)
Verdict: APPROVE WITH COMMENTS · 1 inline, 0 off the diff
Good
- Matches the card: the one-wing guards in
make_dual_shadowandlinearizeare removed, and the only new source isunrefined_deform!(body_aero, ...);git diff 246237a --statshows +103/−41 across the 4 files the card names Ureally is the total number of unrefined sections across wings (src/solver.jl:194sumsn_unrefined_sections), son_results = 6 + Ugives the same size the oldlength(moment_unrefined_dist)did- Angles are split per wing in the same order
calc_forces!fillsmoment_unrefined_dist(theunrefined_idx += wing.n_unrefined_sectionsloop atsrc/solver.jl:474-520), so inputs and outputs line up - Three validation branches became one loop with no change in behaviour except the error message the card mentions; no test checks the old 'Cannot use theta_idxs' text (grep finds none)
- Dropping
smooth=falsechanges nothing: it is already the default inunrefined_deform!(wing, ...; smooth=false)atsrc/wing_geometry.jl:428 - The far-apart testset would catch a wrong offset: if wing 2 were handed wing 1's slice, the second diagonal block would be zero or off by O(1) against
own_first - The renames (
om→omega,be→ad_backend,s→section) and thewing_pairhelper are named in the card as cleanup and are plain Julia locals and test code, not API - The new docstring is reachable: the bare
unrefined_deform!entry indocs/src/private_functions.md:84picks up every method's docstring - Every added line fits in 92 columns; the long lines in
src/body_aerodynamics.jlwere already there
Not good
test/body_aerodynamics/test_body_aerodynamics.jl:536—delta_idxsis split per wing, but the INVISCID wings ignore deflection, so every delta column is zero and no assertion reads them. A swapped or shifted delta offset inunrefined_deform!(body_aero, ...)would pass both testsets.- The far-apart test uses
rtol=1e-4and a1e-4cross-block bound, but the card measured 1.3e-12 and 5.7e-9, so the test allows about 8 orders of magnitude more than it needs to pin the split unrefined_deform!(body_aero, ...)is a third place that works out per-wing unrefined offsets (withcalc_forces!andcalculate_results); a shared per-wing range helper would give one source for that order- If one wing has no
non_deformed_sections, the per-wing call now throws 'Call refine!' even for an empty view, where the old code gave a clear idxs error; this is an edge case and nothing tests it - The shadow body built from wings with different panel counts dispatches dynamically, and no test covers it; the card flags this and it is not blocking
- The card lists the ELLIPTIC guard and
wings[1].spanwise_directionincalc_forces!as known limits but links no follow-up issue; now thatlinearizereaches the second one, it should have an issue
claude, rubric CLEAN_CODE.md. A different lab from the implementer
on purpose: a reviewer sharing its blind spots would not flag its mistakes.
| solver = Solver(body_aero; use_gamma_prev=false, rtol=1e-10) | ||
| y0 = [zeros(2n_sections); body_aero.va; zeros(3)] | ||
| return VortexStepMethod.linearize(solver, body_aero, y0; | ||
| theta_idxs=1:n_sections, delta_idxs=n_sections+1:2n_sections, |
There was a problem hiding this comment.
MINOR: delta_idxs is split per wing, but the INVISCID wings ignore deflection, so every delta column is zero and no assertion reads them. A swapped or shifted delta offset in unrefined_deform!(body_aero, ...) would pass both testsets.
There was a problem hiding this comment.
Fixed in 574b15b: the new testset "unrefined_deform! hands each wing its own run of angles" fails when wing 2 is handed wing 1's deflections (4884 passed, 1 failed).
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Local full suite: PASS (8 min, Julia 1.12.7, one cell of the matrix) |
…t-a- Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Address the comments, fix the conflicts, and open a new issue to allow multi-wing to work with elliptic distribution. |
…e split unrefined_section_range(body_aero, wing_idx) replaces the running offsets in calc_forces! and unrefined_deform!(body_aero, ...). A new testset checks that each wing receives its own twist and deflection angles, which the INVISCID Jacobian tests could not see, and the far-apart Jacobian bounds are tightened to what they measure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t-a- Keeps main's va_vec and this branch's omega in linearize. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Conflicts: merged main in 4ccdea6 and again in 0b28330. In the second merge, |
TL;DR
linearizeandmake_dual_shadowno longer throw on a body with more than one wing: the dual shadow copies every wing, andtheta_idxs/delta_idxsrun over the unrefined sections of all wings in order. #330's stability derivatives need this to cover multi-wing bodies.What changed
Only the one-wing guards stood in the way.
solve!already handled several wings, andcalc_forces!already filledmoment_unrefined_distwing by wing, offset by the section counts of the wings before. The inputs now use that same order, from the same place.make_dual_shadowbuilds the shadow body from_wing_with_eltypeof every wing, not justwings[1]. It also passes on Add the Gaunaa et al. 2024 spanwise-flow viscous drag correction as an opt-in solver setting #352'sis_with_viscous_drag_correction, which came in with the merge from main.unrefined_section_range(body_aero, wing_idx)gives the indices of one wing's unrefined sections.calc_forces!now uses it instead of its own running offset, so the outputs and the inputs share one definition of the order.unrefined_deform!(body_aero, theta_angles, delta_angles)hands each wing a view of its own range of angles.linearizecalls it, thenreinit!as before.linearizecheckstheta_idxs/delta_idxsagainstU, the solver's total number of unrefined sections, which is also the length ofmoment_unrefined_dist. The result length is6 + U.omis renamedomegaandbeis renamedad_backend.sis renamedsectionin_wing_with_eltype.smooth=falseargument is no longer passed.wing_pairtest helper replaces four copies of the same two-wing setup.Tests
Three testsets under
solve! on a two-wing bodyintest/body_aerodynamics/test_body_aerodynamics.jl.unrefined_deform!on the body with a different twist and deflection for every section must give each wing the sametheta_distanddelta_distas deforming that wing on its own with its range of angles. The expected ranges are written out by hand, not taken from the helper. The INVISCID Jacobians below cannot see deflection, so this is the only check on the deflection split.AutoFiniteDiff(steps 1e-6) to a relative difference of 2.7e-7. The test allows 1e-4.Notes for the reviewer
theta_idxsnow gets the length-mismatchArgumentErrorinstead of "Cannot use theta_idxs…". It is the same exception type.solve!andlinearizeon a multi-wing body throw withtype_initial_gamma_distribution=ELLIPTIC, from the guard incalculate_circulation_distribution_elliptical_wing. The default (ZEROS) works. Follow-up: ELLIPTIC initial circulation for a body with more than one wing #357.linearize:calc_forces!andcalculate_resultsusewings[1].spanwise_directionfor the force directions of every panel, so wings with different span directions (a vertical fin, say) get wrong forces from wing 2 onward. The fix changes results, so it is not made here. Follow-up: calc_forces! and calculate_results use the first wing's spanwise_direction for the panels of every wing #358.unrefined_deform!(body_aero, ...):BodyAerodynamicsrefuses a wing that has not been refined ("Wing 2 has not been refined"), and refining needs sections..github/workflows/CI.ymlstill setsfail-fast: false. That is a separatecleanup:PR, not done here.Verification
linearizetestsets errored withArgumentError: Linearization only works for a body_aero with one wing(12 passed, 2 errored), on the first version of those tests.delta_angles[1:3],test_body_aerodynamics.jlgives 4884 passed, 1 failed (the new testset,delta_distof wing 2). All other tests, the Jacobian tests included, still passed. Restored: 4885/4885.test_body_aerodynamics.jl4885,test/solver/test_unrefined_dist.jl40,test/solver/test_forwarddiff.jl7,test/solver/test_viscous_drag_correction.jl90 (includescalc_forces!zero-alloc),test/body_aerodynamics/test_results.jl30,test/solver/test_solver.jl34. No failures.CHANGELOG.mdconflicted and both entries are kept. The second brought in 83867a3 (Name the apparent wind va, va_vec and va_dist everywhere except the public API #349's va rename, Zero the damping correction when smooth_circulation! skips smoothing, and cover it and lei_poly_coeffs with unit tests #328), where one set of lines inlinearizeconflicted: main renamedvatova_vecand this branch renamedomtoomega, and both renames are kept.test_body_aerodynamics.jl4885,test/solver/test_forwarddiff.jl7,test/body_aerodynamics/test_results.jl30,test/solver/test_unrefined_dist.jl40,test/solver/test_viscous_drag_correction.jl90,test/solver/test_solver.jl41. No failures.Julia 1.12 - ubuntu-latestfailed only test_forwarddiff.jl's POLAR_MATRICES check flakes at ~4%, and the oper #287's POLAR_MATRICES check (0.0460232000169766, table A), and this PR's tests passed in that job.Documentationjob passes on 0b28330.unrefined_section_rangeis listed indocs/src/private_functions.md. No REUSE in this repo.Vector{Wing{P,TD} where P}, as the Float64 body already has. It works but dispatches dynamically, and no test covers mixed panel counts.Scope
+135 / −47 across 5 files.
src/solver.jlshrinks (−13 net): three per-wing checks became one loop, andcalc_forces!lost its running offset.src/body_aerodynamics.jl+31 is the range helper and the body method. The test file's +67 net is the three testsets and thewing_pair/linearize_bodyhelpers.Closes #344 · task
VortexStepMethod.jl-344