Skip to content

[FEATURE] Serialize custom callables as inert sentinels instead of raising on save #269

Description

@camUrban

Problem Statement

Saving a simulation fails outright if it contains any custom callable. _serialize_value recognizes only the built-in "sine" and "uniform" spacing functions and raises a ValueError for anything else. This affects three cases: custom spacing functions on the movement classes, the custom second-derivative callables in AeroelasticWingMovement's spacingAnglesSecondDerivative_Gs_to_Wn_ixyz slot, and external_loads_fn on FreeFlightUnsteadyProblem. An aeroelastic simulation with custom flapping spacing or a free-flight simulation with a custom loads function cannot be saved at all, even though the load path never invokes these callables for a solved simulation. The movement histories are reconstructed by aliasing into the serialized steady problems, and the MuJoCo engine is rebuilt from its stored XML, so the callables in a saved solve are pure definition metadata.

Location(s): pterasoftware/_serialization.py, pterasoftware/problems.py, pterasoftware/movements/aeroelastic_wing_movement.py

Proposed Solution

  1. Serialize an unrecognized callable as an inert marker instead of raising. The marker records the callable's qualified name, its source text when inspect.getsource can retrieve it, and a hash of that source. Nothing stored in the file is ever executed, so the no-code-execution guarantee of the JSON format is unchanged.
  2. Deserialize the marker to a sentinel object that behaves like the missing callable's placeholder: loading always succeeds, and the sentinel raises a descriptive error only if it is actually invoked, naming the original function and printing the stored source so the user can reconstruct it.
  3. Add a rebind mechanism so a user who wants to re-solve or regenerate motion after loading can supply the original functions again, with a warning if a rebound function's source hash differs from the recorded one.
  4. Update the tests that currently pin the raise-on-save behavior for custom spacing functions and external_loads_fn to pin the new marker and sentinel behavior instead.

Additional Context

This interacts with #240 (pause and resume unsteady simulations) and should land first. Resume re-invokes exactly the callables this issue makes deferrable: external_loads_fn runs every free-flight time step, the second-derivative callables run every aeroelastic time step via _generate_inertial_moment_function, and spacing functions run when a resumed simulation is extended with new time steps. Without this change, a mid-run aeroelastic or free-flight checkpoint with custom callables could not even be saved, so #240 could not cover all three unsteady solvers. The resume entry point designed under #240 should accept rebind arguments for these callables, detect sentinels eagerly at the resume call rather than failing mid-step, and use the stored source hash to warn when a rebound function differs from the one the checkpoint was created with.

Metadata

Metadata

Assignees

Labels

featureNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions