scenarioCompareFlexPanels

Fourth scenario in the dynamics-engine comparison series (see scenarioCompareOrbit for the introduction).

This scenario approximates structural flexibility by discretizing each of two solar arrays into a serial chain of N rigid segments connected by torsional spring-damper hinges. Sweeping N varies the model dimensionality (the state size grows with the number of hinges) and shows how each engine’s wall-clock cost scales with complexity.

The same physical chain is built three ways so the two Backsubstitution effector implementations can be timed head to head against the recursive engine. On the BSM side each array is either a C++ Module: nHingedRigidBodyStateEffector (panels added through addHingedPanel) or a C++ Module: spinningBodyNDOFStateEffector (an N-link chain of SpinningBody objects); both are advanced by the same Backsubstitution hub solve but differ in implementation maturity. On the MuJoCo side each array is a serial chain of N hinge-jointed child bodies. To match the chain geometry across all three, each segment’s center of mass is offset by -d along its local x-axis and the next hinge attaches at the segment’s far end (-2d); the spring stiffness and damping are applied on each joint.

The default sweep is N = 1, 2, 4, 8, 16, 32. The integration time step scales with N because segment stiffness grows as the segments shrink, so a fixed step adequate for a few large segments would under-resolve the many-segment cases. The timing measurement uses a fixed step budget at each N so the wall-clock reflects per-step cost as a function of model size. Pass a smaller nSegmentsList (as the unit test does) to keep the runtime short.

The script is found in the folder basilisk/examples/dynamicsComparison and executed by using:

python3 scenarioCompareFlexPanels.py

Illustration of Simulation Results

Note

The automated documentation build uses the reduced profile N = 1, 2, 4, 8 to bound CI time. The figures below therefore do not contain the N = 16 or N = 32 cases and should not be used to infer asymptotic scaling. Run this script directly with its defaults to generate the complete six-point study.

The two engines agree to round-off at all four dimensionalities in the reduced documentation profile.

../../_images/scenarioCompareFlexPanels_validity.svg

Within this reduced range, the wall-clock cost of both engines grows with the number of flexible degrees of freedom. The complete default sweep is required before comparing broader scaling behavior.

../../_images/scenarioCompareFlexPanels_runtime.svg

Next comparison: scenarioCompareOrbitMultibody returns the articulated model to orbit and examines differential point-gravity forces.

scenarioCompareFlexPanels.buildBSM(nSegments, dt, record)[source]

Build (and initialize) the Backsubstitution (BSM) chained-panel simulation.

Parameters:
  • nSegments (int) – number of segments per chain

  • dt (float) – integrator time step [s]

  • record (bool) – if True, attach a hub-state recorder

Returns:

(scSim, recorder, handles).

Return type:

tuple

scenarioCompareFlexPanels.buildBsmNDOF(nSegments, dt, record)[source]

Build the BSM chained-panel simulation with the N-DOF spinning-body effector.

Models the identical flexible chain as buildBSM() (same segment mass, inertia, hinge stiffness/damping, geometry, and root deflection) but expressed with C++ Module: spinningBodyNDOFStateEffector instead of C++ Module: nHingedRigidBodyStateEffector, so the two Backsubstitution effector implementations can be timed head to head. Both ride the same Backsubstitution hub solve; only the appendage effector differs.

Parameters:
  • nSegments (int) – number of segments per chain

  • dt (float) – integrator time step [s]

  • record (bool) – if True, attach a hub-state recorder

Returns:

(scSim, recorder, handles).

Return type:

tuple

scenarioCompareFlexPanels.buildMujoco(nSegments, dt, record)[source]

Build (and initialize) the MuJoCo chained-panel simulation.

Parameters:
  • nSegments (int) – number of segments per chain

  • dt (float) – integrator time step [s]

  • record (bool) – if True, attach a hub-state recorder

Returns:

(scSim, recorder, handles).

Return type:

tuple

scenarioCompareFlexPanels.measureWallClocks(buildFuncs, nSegments, dt)[source]

Time a fixed step budget for several implementations in alternating order.

Parameters:
  • buildFuncs (sequence) – simulation builders such as buildBSM and buildMujoco

  • nSegments (int) – number of segments per chain

  • dt (float) – integrator time step [s]

Returns:

one {"median", "min", "std"} timing dictionary per builder [s].

Return type:

list

scenarioCompareFlexPanels.mujocoModel(nSegments)[source]

Return the MJCF model: hub with two N-segment hinged chains.

Parameters:

nSegments (int) – number of segments per chain

Returns:

MJCF XML string.

Return type:

str

scenarioCompareFlexPanels.panelRootDcm(sign)[source]

Return the root-frame DCM that makes both panel chains extend outward.

scenarioCompareFlexPanels.plotResults(rows)[source]

Build the scenario figures.

Parameters:

rows (list) – per-N metric dictionaries from runOne()

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareFlexPanels.relativePrincipalAngle(sigmaBSM, sigmaMujoco)[source]

Per-sample principal rotation angle between two MRP attitude histories.

Parameters:
  • sigmaBSM (numpy.ndarray) – BSM MRP history, shape (N, 3)

  • sigmaMujoco (numpy.ndarray) – MuJoCo MRP history, shape (N, 3)

Returns:

principal angle per sample [rad].

Return type:

numpy.ndarray

scenarioCompareFlexPanels.run(showPlots=False, saveJson=False, nSegmentsList=(1, 2, 4, 8, 16, 32), resultsDir=None)[source]

Main function, see scenario description.

Parameters:
  • showPlots (bool, optional) – if True, plot and show the simulation results. Defaults to False.

  • saveJson (bool, optional) – if True, write the comparison metrics to results/scenarioCompareFlexPanels.json. Defaults to False.

  • nSegmentsList (tuple, optional) – per-chain segment counts to sweep. Defaults to (1, 2, 4, 8, 16, 32). The unit test passes a smaller sweep to keep the runtime short.

  • resultsDir (str, optional) – explicit artifact directory. Defaults to the scenario results folder.

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareFlexPanels.runOne(nSegments, accuracyWindow)[source]

Validate accuracy and benchmark a single dimensionality.

Parameters:
  • nSegments (int) – number of segments per chain

  • accuracyWindow (float) – duration of the accuracy comparison [s]

Returns:

metrics for this N (DOF, attitude error, wall-clock per engine).

Return type:

dict

scenarioCompareFlexPanels.segmentHalfLength(nSegments)[source]

Half-length d of one chain segment [m].

scenarioCompareFlexPanels.segmentInertia(nSegments)[source]

Slender-bar inertia tensor of one chain segment about its center of mass.

Parameters:

nSegments (int) – number of segments per chain

Returns:

3x3 inertia tensor [kg*m^2].

Return type:

numpy.ndarray

scenarioCompareFlexPanels.segmentMass(nSegments)[source]

Mass of one chain segment [kg].

scenarioCompareFlexPanels.timeStep(nSegments)[source]

Integrator step that resolves the stiffest segment oscillation [s].

Parameters:

nSegments (int) – number of segments per chain

Returns:

integrator time step [s].

Return type:

float