Skip to content

Add multi-frame orientations to SysState (Qw/Qx/Qy/Qz)#123

Merged
1-Bart-1 merged 10 commits into
mainfrom
sysstate-orients
Jun 20, 2026
Merged

Add multi-frame orientations to SysState (Qw/Qx/Qy/Qz)#123
1-Bart-1 merged 10 commits into
mainfrom
sysstate-orients

Conversation

@1-Bart-1

Copy link
Copy Markdown
Member

Summary

Replaces the single orient quaternion in SysState with component-major
arrays Qw/Qx/Qy/Qz — one entry per oriented frame — mirroring how
positions are stored as X/Y/Z. This lets a log carry orientations for multiple
wings and/or rigid bodies (e.g. a chain of rigid-body beam segments), not just a
single kite.

SysState gains a second type parameter O (number of oriented frames);
SysLog and Logger thread it through.

Backwards compatibility

Preserved via property views and UnionAll dispatch:

  • ss.orient aliases frame 1 as a mutable view, so both ss.orient .= q
    and ss.orient = q keep working.
  • ss.orients[i] and ss.pos[i] are mutable per-entity views.
  • SysState{P}() still constructs (O defaults to 1); SysState{P} is the
    SysState{P,O} where O UnionAll, so existing f(::SysState{P}) where P
    dispatch and isa SysState{P} still match. Same for SysLog{P}.
  • A StructArray{<:SysState} / SysLog .orient accessor returns a
    per-timestep quaternion column (syslog.orient[k] unchanged for callers).
  • load_log reads both new (Qw/...) and legacy (orient) Arrow logs.
  • show still prints a single orient line.

Tests

Pkg.test() passes (Logfiles 29/29). The two schema-coupled assertions in
test-logfiles.jl were updated for the 2-parameter type (SysState{7,1}).

🤖 Generated with Claude Code

Replace the single `orient` quaternion with component-major arrays Qw/Qx/Qy/Qz
(one entry per oriented frame), mirroring the X/Y/Z position layout. SysState
gains a second type parameter O (number of oriented frames); SysLog and Logger
follow.

Backwards compatibility is preserved via property views:
- `ss.orient` aliases frame 1 (mutable, so `.= ` and `= ` both work)
- `ss.orients[i]` / `ss.pos[i]` are mutable per-entity views
- `SysState{P}()`/`SysState{P}` keep working (O defaults to 1; the 1-arg form
  is the `SysState{P,O} where O` UnionAll, so existing dispatch still matches)
- the StructArray/SysLog `.orient` accessor returns a per-timestep column
- `load_log` reads both new (Qw/...) and old (`orient`) Arrow logs
- `show` still displays a single `orient` line

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

codecov-commenter commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.05479% with 70 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/sysstate_views.jl 39.70% 41 Missing ⚠️
src/build.jl 0.00% 14 Missing ⚠️
src/KiteUtils.jl 75.00% 6 Missing ⚠️
src/load_log.jl 66.66% 5 Missing ⚠️
src/_load_log.jl 0.00% 2 Missing ⚠️
src/logger.jl 33.33% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

1-Bart-1 and others added 3 commits June 17, 2026 22:28
Round out the SysState property views on the log side: `StructArray{<:SysState}`
and `SysLog` now expose `.orients[frame][t]` and `.pos[point][t]` (lazy
per-entity time series) alongside the existing `.orient`. Fixes
`syslog.syslog.orients` erroring through the StructArray getproperty shim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keeping version at 0.12.0 made the workspace unresolvable: examples
depends on KiteViewers, whose latest release caps KiteUtils at 0.11,
so no KiteViewers version is installable against 0.12.0 — breaking both
the docs and test environments (shared workspace manifest).

Revert version to 0.11.8 (within KiteViewers' compat range) and mark the
changelog section as unreleased; the breaking bump lands when tagging,
once KiteViewers supports it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@1-Bart-1 1-Bart-1 requested a review from ufechner7 June 17, 2026 21:38

@ufechner7 ufechner7 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Question: Why is this a breaking release, if you added backward compatible wrappers?

JETLS gives the following warnings:

ufechner@framework:~/repos/KiteUtils/bin$ ./jetls
# Analyzed 15 files in 23.57s                                                  
# Found 2 diagnostics in 1 file (2 warnings)

# @ src/sysstate_views.jl:28,1
@inline function Base.setindex!(q::FrameQuat, v, i::Int)
    field = (:Qw, :Qx, :Qy, :Qz)[i]
    @inbounds getfield(q.ss, field)[q.k] = v
└──────────────────────────────────────────┘ ── no matching method found `setindex!(::Float32, ::Bool, ::Int64)`, `setindex!(::Float64, ::Bool, ::Int64)`, `setindex!(::Int16, ::Bool, ::Int64)` (3/4 union split) [warn:inference/method-error]
end

# @ src/sysstate_views.jl:28,1
@inline function Base.setindex!(q::FrameQuat, v, i::Int)
    field = (:Qw, :Qx, :Qy, :Qz)[i]
    @inbounds getfield(q.ss, field)[q.k] = v
└──────────────────────────────────────────┘ ── no matching method found `setindex!(::Float32, ::Any, ::Int64)`, `setindex!(::Float64, ::Any, ::Int64)`, `setindex!(::Int16, ::Any, ::Int64)` (3/4 union split) [warn:inference/method-error]
end

This section of the documentation might need an update: https://opensourceawe.github.io/KiteUtils.jl/stable/examples/#The-system-state,-type-SysState

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.

Pull request overview

This PR updates SysState to support multiple orientation frames by replacing the single orient quaternion field with component-major Qw/Qx/Qy/Qz arrays (one value per oriented frame), and threads the new O type parameter through logging (Logger/SysLog) and log I/O. It also introduces view types so existing .orient access remains usable (frame 1).

Changes:

  • Replace SysState’s single quaternion storage with multi-frame quaternion component arrays (Qw/Qx/Qy/Qz) and add O as a second type parameter.
  • Add ergonomic views for per-point positions (.pos[i]) and per-frame orientations (.orients[k]), while keeping legacy .orient (frame 1) working.
  • Update log save/load paths and tests to reflect the new schema and type parameters, including back-compat loading of legacy orient Arrow logs.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/test-logfiles.jl Updates schema-coupled type assertions to SysState{P,1}.
src/sysstate.yaml Replaces orient with Qw/Qx/Qy/Qz component arrays parameterized by O.
src/sysstate_views.jl Adds view types for .orient, .orients, and .pos, plus StructArray column views.
src/logger.jl Updates Logger constructors to include O (defaulting to 1).
src/load_log.jl Adds back-compat logic to load either new Qw... or legacy orient columns.
src/KiteUtils.jl Wires in new view-based getproperty/setproperty! and updates SysLog typing/constructors.
src/build.jl Updates generator templates for the new SysState{P,O} / Logger{P,O,Q} structure.
src/_sysstate.jl Generated: updates SysState definition to SysState{P,O} and adds Qw/Qx/Qy/Qz fields.
src/_syslog.jl Generated: updates syslog(logger) to build StructArray{SysState{P,O}} with quaternion components.
src/_show.jl Generated: keeps a single displayed orient line via the legacy view.
src/_save_log.jl Generated: resizes quaternion component vectors instead of orient_vec.
src/_logger.jl Generated: updates Logger{P,O,Q} fields and preallocation vectors for quaternion components.
src/_log.jl Generated: logs quaternion components (Qw..Qz) instead of orient.
src/_load_log.jl Generated: updated to read Qw..Qz columns (but currently still builds StructArray{SysState{P}}).
src/_demo_syslog.jl Generated: updates demo syslog creation to store Qw..Qz and accept O.
CHANGELOG.md Documents the breaking change and the provided compatibility accessors.

Comment thread src/KiteUtils.jl Outdated
Comment thread src/load_log.jl
Comment thread src/_load_log.jl Outdated
1-Bart-1 and others added 4 commits June 20, 2026 15:11
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@1-Bart-1

1-Bart-1 commented Jun 20, 2026

Copy link
Copy Markdown
Member Author

It is breaking, things can become abstract type which is performance regression. But updating is easy, and the code will probably not error. Still, I will release it as breaking.

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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

Comment thread src/KiteUtils.jl
Comment thread src/sysstate_views.jl Outdated
Comment thread src/sysstate_views.jl Outdated
Comment thread src/sysstate_views.jl Outdated
Comment thread src/sysstate_views.jl Outdated
@1-Bart-1 1-Bart-1 merged commit 35e8b86 into main Jun 20, 2026
3 checks passed
@1-Bart-1 1-Bart-1 deleted the sysstate-orients branch June 20, 2026 14:37
1-Bart-1 added a commit to OpenSourceAWE/SymbolicAWEModels.jl that referenced this pull request Jun 22, 2026
* Separate out aero to component

* Fix for tests

* Restore speed_controlled winch flag

The winch-interface refactor (#210) dropped the `speed_controlled`
field, which broke the V3Kite flight-replay path that prescribes
reel-out velocity from recorded CSV data.

Add it back as a runtime-switchable flag: when `winch.speed_controlled`
is true, `winch_acc` is forced to 0 (ignoring the winch component's
`acc` output), so `D(winch_vel) = 0` and velocity is prescribed via
`winch.vel`. Implemented with the registered `get_speed_controlled`
accessor so it takes effect without recompiling, matching the
pre-refactor behavior.

Caveat: the model cache key (set_hash + sys_struct_hash) does not
capture this equation change, so existing cached binaries must be
rebuilt (remake=true) for the restored branch to take effect.

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

* Update psys

* Add cache test

* Fix docs

* Dont use useless abbreviations

* Improved check

* Use dispatch field instead of func

* Update default manifests

* Merge plate into group and rename to twistsurface

* Merge wing types into one Wing; route plate aero through aero_component

Collapse BaseWing/VSMWing/PlateWing into a single `Wing` type. VSM state
moves into a `VSMEngine` sub-struct on `wing.vsm`. The engine is wing
infrastructure shared by all aero modes — an AeroNone wing still carries it
for section matching and twist-surface geometry — so it lives on the wing,
not in the aero mode. VSMWing/PlateWing become constructor functions that
return a Wing; `wing isa VSMWing/PlateWing` become `is_vsm`/`is_plate`.

Flat-plate aero now goes through `aero_component(::AeroPlate, ...)` on the
same PARTICLE connector contract as the other per-point modes, extended
with per-point `va`/`rho` (the only inputs plate needs; VSM particle modes
ignore them). Deletes plate_eqs.jl and its bespoke wiring branch.

RHS aero getters are function-barriered on the concrete VSMEngine for
type-stable, allocation-free reads. Full suite green (1174/1174), zero alloc.

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

* Refactor aero updates to be dispatch-based

* Improve code quility

* Restructure files

* Remove _ prefixes

* Use dispatches instead of is vsm

* Refactor plotting

* Use normalized inertia

* Dont display z offset

* Improve plotting

* Fix docs

* Update default manifests

* Add continuous aero mode

* Add continuous billowing aero mode

* Read yaml density

* Sync densities and tighten tols

* Add reusable RigidBody component, 6-DOF elastic joint, and rigid-body replay

Extract the QUATERNION wing's 6-DOF dynamics into a shared generator and build a
standalone multi-rigid-body capability on top of it.

- rigid_body_eqs!: generic 6-DOF generator (quaternion kinematics + Euler +
  Newton + body-frame output) driven by a total force/moment at the COM, with
  optional integration overrides for pinning/damping. wing_eqs! now delegates to
  it (behaviour-equivalent; wing tests green).
- RigidBody: standalone component (own collection, accessors, state
  serialization, getter, update, cache hash, init) reusing rigid_body_eqs!.
  Specified by mass/inertia/ICs + gravity + a settable external wrench; a `fixed`
  flag freezes all DOF.
- ElasticJoint: 6-DOF elastic connection between two rigid bodies (EA/GA/GJ/EI +
  damping), equal-and-opposite wrench into both bodies' load accumulators.
- Logging/replay: SysState/Logger now carry rigid-body positions (X/Y/Z) and
  per-wing/per-body orientation frames (KiteUtils orients); update_from_sysstate!
  reconstructs them; the Makie ext draws bodies (and wings) as RGB body-frame
  triads from the orientation quaternion. New position_slots(sys_struct) is the
  single source of truth for the X/Y/Z slot layout.

Tests: test_rigid_body (free-fall, spin-up, COM-offset), test_joint (axial &
torsional frequency, momentum conservation), test_beam_replay (SysLog round-trip
+ reconstruction). Example: beam_6dof_joints.jl (10-segment cantilever).

Depends on KiteUtils orients (OpenSourceAWE/KiteUtils.jl#123).

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

* Add option to use interp

* Flatten RHS struct reads into MTK params; concrete-type wing/engine (2.76x RHS)

Replace the hottest @register_symbolic struct reads in the ODE RHS with flat MTK
parameters synced once per step, and concretely type the wing's aero/engine so
the abstract-field tax disappears.

- Wing{A<:AbstractAeroModel} (aero::A) + parametric AeroLinearized/AeroDirect/
  ContinuousAero{E}; engine built and attached (attach_engine\!) before the wing
  is constructed. Removes the datatype.c offset lookup + the per-coefficient
  dispatch on the abstract VSMEngine.
- flat_params.jl: path-based `params` view mirroring sys_struct, scalar/array/
  callable parameters, and a sync (build_param_sync/sync_params\!) with
  subsystem name-matching across the aero_1+... namespace boundary.
- Flatten aero coeffs (aero_y/x/jac, drag_frac), segment fields, and joint
  stiffness/damping; joint interpolation stiffness via callable params (no
  @register_symbolic). rotation_matrix_to_quaternion rewritten with ifelse so it
  is symbolic (-4 registers), computed once and CSE-shared.

RHS 3.79 -> 1.375 us (2.76x), 0 allocations; full test suite 1739/1739.

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

* Flatten top-level data getters into MTK params (3.17x RHS)

Convert the remaining equation-level data reads (points, segments, wings, twist
surfaces, pulleys, rigid bodies, settings, winch top-level) from
@register_symbolic getters to flat params via the path-based `params` view.

Rules established:
- Equations -> flat params; defaults/guesses (initial conditions) keep registered
  getters, since a param referenced only in a default is pruned by mtkcompile.
- psys must stay anchored in an equation (calc_wind_factor for point models;
  get_body_R_b_to_p for point-less rigid-body/joint/beam models).
- Genuine functions (calc_wind_factor, joint interpolation, polars) stay
  registered; only data is flattened. Reverted the callable-param mechanism.
- Custom winch components keep registered getters (params kwarg would break the
  user-defined winch.model interface).

RHS 3.79 -> 1.197 us (3.17x), 0 allocations; full test suite 1739/1739.

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

* Flatten aero-mode subsystem data getters (direct/continuous/plate)

Convert the per-subsystem data reads to flat params, added to each component's
System parameter list (synced via the namespace-matching path):
- AeroDirect: frozen force/moment/per-twist-moment overrides (provides_aero_override
  and stores_point_force are constant-true for AeroDirect, so the conditions bake
  away) -> params.{wings,points}.aero_force_b / aero_moment_b / aero_moment.
- ContinuousAero: frozen induced velocity -> params.wings[w].aero.v_ind.
- AeroPlate: section chord/y_airf/twist/area + drag_corr -> flat params.
The alpha-dependent polars (get_plate_cl/cd, get_continuous_cl/cd/cm) stay
@register_symbolic (genuine functions), which also keeps psys anchored in those
subsystems.

test_aero_modes 500/500, test_continuous_aero 19/19, test_match_aero_sections 144/144.

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

* Update plan: data flattening complete (3.17x, 1739/1739)

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

* Remove dead @register_symbolic getters (data now flat params)

Delete the ~65 now-unused registered getters from accessors.jl (537 -> 148
lines) plus the engine_aero_* barriers and the dead plate/continuous data getters
(get_plate_drag_corr, get_twist_surface_area, get_continuous_v_ind,
induced_velocity_component); their struct reads are flat MTK params now.

Kept (still used): initial-condition getters (defaults/guesses can't be flat
params), genuine functions (joint interpolation, polars), the psys anchor
get_body_R_b_to_p, and the winch-component getters. get_wind_vec stays as a plain
computed reader for the wind_vec flat param (no longer @register_symbolic).

test_bench.jl: drop the per-getter allocation tests (getters gone; the RHS
0-allocation test is the guard).

Full suite 1727/1727.

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

* Update plan: dead-code deletion done (1727/1727); note Initial() IC option

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

* Initialize ODE state via MTK Initial() params

Replace parameter-dependent IC defaults (which became initialization
equations reading the live `psys`) with build-time constant defaults, so
MTK exposes settable `Initial(state)` parameters. A new `initial` view
(initial_conditions.jl) mirrors the flat `params` view: `bind_initial\!`
records each struct-field -> state-variable binding and bakes the constant
default. After compilation `build_initial_sync` builds a setter over the
`Initial` params (kept when `is_parameter(sys, Initial(var))`, which holds
for surviving unknowns and observed vars solved at init), and
`sync_initial\!` pushes the live `SystemStructure` state onto them before
each fresh `init`.

reinit\! now syncs params and ICs onto the problem and runs a single init
on the fresh path, dropping the trailing `reinit\!(...; reinit_dae)` there:
that re-solve does not re-read `Initial` and discarded the synced state for
PARTICLE wings. The reinit_dae path is kept only when reusing an existing
integrator. Removes the reset_vel ODEProblem-rebuild hack.

Full suite green (1727/1727); RHS still 0 allocations.

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

* Remove quasi static because it is not used

* Remove dead getters

* Remove almost all register symbolic

* Add example to fit beam stiffness

* Remove all register symbolic

* Fix docs

* Don't run refresh twice

* Monolith inplace getter

* Remove tether props func

* Useless bench

* Fix aqua failure

* Remove plan

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1-Bart-1 added a commit to OpenSourceAWE/SymbolicAWEModels.jl that referenced this pull request Jun 28, 2026
* Separate out aero to component

* Fix for tests

* Restore speed_controlled winch flag

The winch-interface refactor (#210) dropped the `speed_controlled`
field, which broke the V3Kite flight-replay path that prescribes
reel-out velocity from recorded CSV data.

Add it back as a runtime-switchable flag: when `winch.speed_controlled`
is true, `winch_acc` is forced to 0 (ignoring the winch component's
`acc` output), so `D(winch_vel) = 0` and velocity is prescribed via
`winch.vel`. Implemented with the registered `get_speed_controlled`
accessor so it takes effect without recompiling, matching the
pre-refactor behavior.

Caveat: the model cache key (set_hash + sys_struct_hash) does not
capture this equation change, so existing cached binaries must be
rebuilt (remake=true) for the restored branch to take effect.

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

* Update psys

* Add cache test

* Fix docs

* Dont use useless abbreviations

* Improved check

* Use dispatch field instead of func

* Update default manifests

* Merge plate into group and rename to twistsurface

* Merge wing types into one Wing; route plate aero through aero_component

Collapse BaseWing/VSMWing/PlateWing into a single `Wing` type. VSM state
moves into a `VSMEngine` sub-struct on `wing.vsm`. The engine is wing
infrastructure shared by all aero modes — an AeroNone wing still carries it
for section matching and twist-surface geometry — so it lives on the wing,
not in the aero mode. VSMWing/PlateWing become constructor functions that
return a Wing; `wing isa VSMWing/PlateWing` become `is_vsm`/`is_plate`.

Flat-plate aero now goes through `aero_component(::AeroPlate, ...)` on the
same PARTICLE connector contract as the other per-point modes, extended
with per-point `va`/`rho` (the only inputs plate needs; VSM particle modes
ignore them). Deletes plate_eqs.jl and its bespoke wiring branch.

RHS aero getters are function-barriered on the concrete VSMEngine for
type-stable, allocation-free reads. Full suite green (1174/1174), zero alloc.

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

* Refactor aero updates to be dispatch-based

* Improve code quility

* Restructure files

* Remove _ prefixes

* Use dispatches instead of is vsm

* Refactor plotting

* Use normalized inertia

* Dont display z offset

* Improve plotting

* Fix docs

* Update default manifests

* Add continuous aero mode

* Add continuous billowing aero mode

* Read yaml density

* Sync densities and tighten tols

* Add reusable RigidBody component, 6-DOF elastic joint, and rigid-body replay

Extract the QUATERNION wing's 6-DOF dynamics into a shared generator and build a
standalone multi-rigid-body capability on top of it.

- rigid_body_eqs!: generic 6-DOF generator (quaternion kinematics + Euler +
  Newton + body-frame output) driven by a total force/moment at the COM, with
  optional integration overrides for pinning/damping. wing_eqs! now delegates to
  it (behaviour-equivalent; wing tests green).
- RigidBody: standalone component (own collection, accessors, state
  serialization, getter, update, cache hash, init) reusing rigid_body_eqs!.
  Specified by mass/inertia/ICs + gravity + a settable external wrench; a `fixed`
  flag freezes all DOF.
- ElasticJoint: 6-DOF elastic connection between two rigid bodies (EA/GA/GJ/EI +
  damping), equal-and-opposite wrench into both bodies' load accumulators.
- Logging/replay: SysState/Logger now carry rigid-body positions (X/Y/Z) and
  per-wing/per-body orientation frames (KiteUtils orients); update_from_sysstate!
  reconstructs them; the Makie ext draws bodies (and wings) as RGB body-frame
  triads from the orientation quaternion. New position_slots(sys_struct) is the
  single source of truth for the X/Y/Z slot layout.

Tests: test_rigid_body (free-fall, spin-up, COM-offset), test_joint (axial &
torsional frequency, momentum conservation), test_beam_replay (SysLog round-trip
+ reconstruction). Example: beam_6dof_joints.jl (10-segment cantilever).

Depends on KiteUtils orients (OpenSourceAWE/KiteUtils.jl#123).

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

* Add option to use interp

* Flatten RHS struct reads into MTK params; concrete-type wing/engine (2.76x RHS)

Replace the hottest @register_symbolic struct reads in the ODE RHS with flat MTK
parameters synced once per step, and concretely type the wing's aero/engine so
the abstract-field tax disappears.

- Wing{A<:AbstractAeroModel} (aero::A) + parametric AeroLinearized/AeroDirect/
  ContinuousAero{E}; engine built and attached (attach_engine\!) before the wing
  is constructed. Removes the datatype.c offset lookup + the per-coefficient
  dispatch on the abstract VSMEngine.
- flat_params.jl: path-based `params` view mirroring sys_struct, scalar/array/
  callable parameters, and a sync (build_param_sync/sync_params\!) with
  subsystem name-matching across the aero_1+... namespace boundary.
- Flatten aero coeffs (aero_y/x/jac, drag_frac), segment fields, and joint
  stiffness/damping; joint interpolation stiffness via callable params (no
  @register_symbolic). rotation_matrix_to_quaternion rewritten with ifelse so it
  is symbolic (-4 registers), computed once and CSE-shared.

RHS 3.79 -> 1.375 us (2.76x), 0 allocations; full test suite 1739/1739.

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

* Flatten top-level data getters into MTK params (3.17x RHS)

Convert the remaining equation-level data reads (points, segments, wings, twist
surfaces, pulleys, rigid bodies, settings, winch top-level) from
@register_symbolic getters to flat params via the path-based `params` view.

Rules established:
- Equations -> flat params; defaults/guesses (initial conditions) keep registered
  getters, since a param referenced only in a default is pruned by mtkcompile.
- psys must stay anchored in an equation (calc_wind_factor for point models;
  get_body_R_b_to_p for point-less rigid-body/joint/beam models).
- Genuine functions (calc_wind_factor, joint interpolation, polars) stay
  registered; only data is flattened. Reverted the callable-param mechanism.
- Custom winch components keep registered getters (params kwarg would break the
  user-defined winch.model interface).

RHS 3.79 -> 1.197 us (3.17x), 0 allocations; full test suite 1739/1739.

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

* Flatten aero-mode subsystem data getters (direct/continuous/plate)

Convert the per-subsystem data reads to flat params, added to each component's
System parameter list (synced via the namespace-matching path):
- AeroDirect: frozen force/moment/per-twist-moment overrides (provides_aero_override
  and stores_point_force are constant-true for AeroDirect, so the conditions bake
  away) -> params.{wings,points}.aero_force_b / aero_moment_b / aero_moment.
- ContinuousAero: frozen induced velocity -> params.wings[w].aero.v_ind.
- AeroPlate: section chord/y_airf/twist/area + drag_corr -> flat params.
The alpha-dependent polars (get_plate_cl/cd, get_continuous_cl/cd/cm) stay
@register_symbolic (genuine functions), which also keeps psys anchored in those
subsystems.

test_aero_modes 500/500, test_continuous_aero 19/19, test_match_aero_sections 144/144.

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

* Update plan: data flattening complete (3.17x, 1739/1739)

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

* Remove dead @register_symbolic getters (data now flat params)

Delete the ~65 now-unused registered getters from accessors.jl (537 -> 148
lines) plus the engine_aero_* barriers and the dead plate/continuous data getters
(get_plate_drag_corr, get_twist_surface_area, get_continuous_v_ind,
induced_velocity_component); their struct reads are flat MTK params now.

Kept (still used): initial-condition getters (defaults/guesses can't be flat
params), genuine functions (joint interpolation, polars), the psys anchor
get_body_R_b_to_p, and the winch-component getters. get_wind_vec stays as a plain
computed reader for the wind_vec flat param (no longer @register_symbolic).

test_bench.jl: drop the per-getter allocation tests (getters gone; the RHS
0-allocation test is the guard).

Full suite 1727/1727.

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

* Update plan: dead-code deletion done (1727/1727); note Initial() IC option

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

* Initialize ODE state via MTK Initial() params

Replace parameter-dependent IC defaults (which became initialization
equations reading the live `psys`) with build-time constant defaults, so
MTK exposes settable `Initial(state)` parameters. A new `initial` view
(initial_conditions.jl) mirrors the flat `params` view: `bind_initial\!`
records each struct-field -> state-variable binding and bakes the constant
default. After compilation `build_initial_sync` builds a setter over the
`Initial` params (kept when `is_parameter(sys, Initial(var))`, which holds
for surviving unknowns and observed vars solved at init), and
`sync_initial\!` pushes the live `SystemStructure` state onto them before
each fresh `init`.

reinit\! now syncs params and ICs onto the problem and runs a single init
on the fresh path, dropping the trailing `reinit\!(...; reinit_dae)` there:
that re-solve does not re-read `Initial` and discarded the synced state for
PARTICLE wings. The reinit_dae path is kept only when reusing an existing
integrator. Removes the reset_vel ODEProblem-rebuild hack.

Full suite green (1727/1727); RHS still 0 allocations.

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

* Remove quasi static because it is not used

* Remove dead getters

* Remove almost all register symbolic

* Add example to fit beam stiffness

* Remove all register symbolic

* Fix docs

* Don't run refresh twice

* Monolith inplace getter

* Remove tether props func

* Useless bench

* Fix aqua failure

* Remove plan

* Attach point to rigid body

* Merge rigid body and wing

* Import Point

* Fix CI

* No multi-line inline comments. Comments should be in docstring or 1-line max.

* Add docstring

* Add fallback

* Remove useless backup

* Try to fix 404

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

4 participants