Skip to content

[BUG] Validate that movements' base geometry is their parents' base geometry #220

Description

@camUrban

Problem Statement

The movement hierarchy stores base geometry references independently at every level, so nothing enforces that wing_movements[i].base_wing is the same object as base_airplane.wings[i], or that wing_cross_section_movements[i].base_wing_cross_section is the same object as base_wing.wing_cross_sections[i]. The same data is reachable through two paths with no guarantee they agree, so a caller can construct a movement hierarchy whose base geometry contradicts itself. This has a concrete consequence today: AeroelasticAirplaneMovement.__init__() rejects an AeroelasticWingMovement whose base Wing has type 4 symmetry (its mirrored half has Panels but no WingCrossSections, so its strips cannot deform), but a base Wing that was never meshed and is not shared with the base Airplane has no symmetry type yet, passes that check, and fails later with an uninformative IndexError deep in the structural solve (see the review discussion on #190).

Location(s): pterasoftware/_core.py, pterasoftware/movements/aeroelastic_airplane_movement.py, pterasoftware/movements/aeroelastic_wing_movement.py

Proposed Solution

  1. In CoreAirplaneMovement.__init__(), validate that wing_movements[i].base_wing is base_airplane.wings[i] for every index. Placing the check at the Core level covers all three hierarchies: the standard classes, AeroelasticAirplaneMovement (which subclasses CoreAirplaneMovement directly), and free flight (whose FreeFlightMovement holds standard AirplaneMovements).
  2. In CoreWingMovement.__init__(), validate that wing_cross_section_movements[i].base_wing_cross_section is base_wing.wing_cross_sections[i] for every index, which likewise covers WingCrossSectionMovement and AeroelasticWingCrossSectionMovement.
  3. Audit the test fixtures and any examples that construct movements around geometry objects not taken from a constructed Airplane, and rework them to satisfy the identity checks.
  4. Because an Airplane's constructor meshes all of its Wings, these checks guarantee that every base Wing reaching AeroelasticAirplaneMovement.__init__() has its symmetry type set, which removes the type 4 rejection's blind spot and converts the IndexError failure mode into the existing clear construction-time ValueError.

Additional Context

This is one instance of a broader parallel-ownership pattern in the movement and problem classes (for example, the coupled problems now derive their initial Airplanes from their movements rather than accepting them as separate arguments). The identity checks proposed here are the narrow, construction-time piece of that cleanup and do not depend on the larger class restructuring.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingmaintenanceImprovements or additions to documentation, testing, robustness, or tooling

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions