Skip to content

feat(vpm): compute in-plane hub force (H-force) in the free-wake march#11

Open
mcroomp wants to merge 1 commit into
mainfrom
feat/vpm-in-plane-hforce
Open

feat(vpm): compute in-plane hub force (H-force) in the free-wake march#11
mcroomp wants to merge 1 commit into
mainfrom
feat/vpm-in-plane-hforce

Conversation

@mcroomp

@mcroomp mcroomp commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #10. The BEM-family models (QS BEM, Pitt-Peters, Oye) now report the in-plane hub force ("H-force"), but the VPM free-wake rotor did not: it accumulated only the out-of-plane thrust and hub moments, then passed 0.0, 0.0 for fx_hub/fy_hub into assemble_result, so F_world carried no in-plane force for VPM.

This PR closes that gap by accumulating the H-force directly in the VPM time-domain loads loop.

What changed

  • dynbem_rs/src/vpm/march.rs — per element, accumulate:

    • fx += dF_t*sin(psi) - dT*sin(beta_b)*cos(psi)
    • fy += dF_t*cos(psi) + dT*sin(beta_b)*sin(psi)

    The first term is the profile/induced-drag H-force (identical pairing to bem_common::SweepCtx::run). The second is the flapping-tilt term, resolved instantaneously from the real per-blade flap DOF beta_b — no b1c/b1s harmonics, and exactly zero for a rigid rotor. Unlike the BEM-family models the VPM needs no apply_flap_dynamics: flapback emerges from the marched disk geometry.

  • dynbem_rs/src/vpm/mod.rs — thread fx_hub/fy_hub through VpmRotorResult and pass them from step() into assemble_result (removed the TODO).

  • validation_rs — new vpm_hforce_directional check: downwind H-force in edgewise flow, ~0 in hover, mostly aligned with the flow axis, larger than the hover baseline. Registered in checks/mod.rs; fixed the VpmRotorResult initializer in cyclic_phase_servo.rs.

  • DocsVPM_DESIGN.md §5.5.5 (hub-load equations) + §8.1 validation table; AGENTS.md new "VPM in-plane H-force" subsection documenting the sign convention.

Sign note

FlightCondition::v_hub is the freestream air velocity in the hub frame (relative wind = v_hub − blade velocity), so a +X freestream yields a downwind +X in-plane force — matching the level-disk crosswind direction validated in checks/h_force.rs.

Validation

  • Full validation_rs suite: 166/166 pass (was 162, +4 new VPM H-force assertions).
  • cargo test --release -p dynbem_rs -- vpm: 18 pass.
  • cargo fmt clean; dynbem PyO3 crate builds.

Note: the untracked steady_flight_simple/ directory is intentionally excluded as unrelated.

The VPM free-wake rotor previously accumulated only the out-of-plane
thrust (and hub moments) and passed 0.0, 0.0 for the in-plane hub force
into assemble_result, so F_world carried no H-force. Accumulate it
directly in the loads loop, per element:

  fx += dF_t*sin(psi) - dT*sin(beta_b)*cos(psi)
  fy += dF_t*cos(psi) + dT*sin(beta_b)*sin(psi)

The first term is the profile/induced-drag H-force (same pairing as
bem_common::SweepCtx::run); the second is the flapping-tilt term,
resolved instantaneously from the real time-domain flap DOF (no b1c/b1s
harmonics, exactly zero for a rigid rotor). Unlike the BEM-family models
the VPM needs no apply_flap_dynamics -- flapback emerges from the marched
disk geometry.

- Thread fx_hub/fy_hub through VpmRotorResult and step()->assemble_result.
- New validation: vpm_hforce_directional (downwind H-force in edgewise
  flow, ~0 in hover). Full suite 166/166 pass.
- Docs: VPM_DESIGN sec 5.5.5 + sec 8.1 table; AGENTS.md H-force section.
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.

1 participant