scenarioCompareParetoRwPanels

Accuracy-versus-runtime Pareto study on the hub-with-reaction-wheels-and-panels system (see scenarioCompareRwPanels for the model, and scenarioCompareOrbit for the introduction to the two dynamics engines).

The earlier comparison scenarios hold the integrator and time step fixed and ask whether the two engines agree. This scenario asks, for each engine: what is the cheapest way to reach a given accuracy? This is the classical work-precision (Pareto) diagram from the numerical-integration literature.

We sweep a family of integrators and accuracy controls:

  • Fixed-step integrators (Euler, RK2, RK4) over a range of time steps.

  • Adaptive Runge-Kutta-Fehlberg integrators (RKF45, RKF78) over a range of error tolerances.

For each configuration and each engine the study measures wall-clock time and final attitude error: the principal rotation angle of the relative direction cosine matrix (as in scenarioCompareTorque) with respect to a reference solution computed for the same engine at a tight tolerance. A per-engine reference isolates the integrator’s work-precision behavior from the formulation difference between the engines, which the other scenarios already characterize.

Note

What the reference “truth” is, and what it is not. The reference is per-engine: each engine’s error is measured against its own tight solution, not against the other engine or a shared analytic truth. These plots therefore rank each engine’s integrator work-precision; they are not a statement of absolute cross-engine accuracy (that is established separately by the fixed-step agreement scenarios and, for the Keplerian case, by the analytic reference in scenarioCompareOrbit).

Plotting error against wall-clock time produces a Pareto front: the lower-left envelope of points is the set of non-dominated (most efficient) configurations. Higher-order integrators occupy the high-accuracy end, while low-order or adaptive integrators with loose tolerances occupy the cheap, low-accuracy end. This system is slow: its fastest mode is resolved at every step size swept, no stability wall is hit, and the front is wide and well populated. Its companion scenarioCompareParetoFlexPanels runs the same sweep on a stability-limited high-frequency array where that wall dominates.

Note

The MJScene runs enable highOrderAttitudeIntegration so the free-joint attitude quaternion is advanced at the integrator’s full order. MuJoCo’s default attitude step (a single exponential map of the stage-averaged body rate) is only second-order accurate on SO(3); that error sits outside the velocity ODE the adaptive controller sees, so tightening the tolerance cannot reduce it. High-order integration removes that floor: the macro step is no longer an accuracy knob, so every adaptive configuration holds it fixed and varies only the tolerance, which drives the error down to machine precision.

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

python3 scenarioCompareParetoRwPanels.py

Illustration of Simulation Results

Note

To bound CI time, the automated documentation build generates these figures from three representative configurations: one RK4, one Euler, and one RKF45 run. They exercise the work-precision workflow but do not constitute the wide, well-populated default Pareto study described above. Run this script directly with its defaults before drawing performance conclusions.

The reduced documentation profile illustrates how the individual configurations and their lower-left envelope are displayed.

../../_images/scenarioCompareParetoRwPanels_pareto.svg

The reduced frontier is a plotting demonstration, not a basis for ranking the engines at unsampled target accuracies.

../../_images/scenarioCompareParetoRwPanels_frontier.svg

The same work-precision analysis is repeated for the hub inertial position error, giving a companion view of the translational coupling alongside the attitude result.

../../_images/scenarioCompareParetoRwPanels_frontierPosition.svg

Next comparison: scenarioCompareParetoFlexPanels repeats the work-precision study on a stability-limited flexible system.

scenarioCompareParetoRwPanels.addInterleavedTimings(bsmRows, mujocoRows)[source]

Attach recorder-free timing statistics, alternating engine order by trial.

scenarioCompareParetoRwPanels.buildBSM(integratorName, dt, tol, record=True)[source]

Build the back-substitution (BSM) hub-wheel-panel simulation with the given integrator.

Parameters:
  • integratorName (str) – integrator attribute in svIntegrators.

  • dt (float) – task (macro) time step [s].

  • tol (float) – adaptive tolerance, or None for fixed-step integrators.

  • record (bool, optional) – attach a final-state recorder. Defaults to True.

Returns:

(scSim, recorder, handles).

Return type:

tuple

scenarioCompareParetoRwPanels.buildMujoco(integratorName, dt, tol, record=True)[source]

Build the MuJoCo hub-wheel-panel simulation with the given integrator.

Parameters:
  • integratorName (str) – integrator attribute in svIntegrators.

  • dt (float) – task (macro) time step [s].

  • tol (float) – adaptive tolerance, or None for fixed-step integrators.

  • record (bool, optional) – attach a final-state recorder. Defaults to True.

Returns:

(scSim, recorder, handles).

Return type:

tuple

scenarioCompareParetoRwPanels.finalState(builder, integratorName, dt, tol)[source]

Propagate one configuration and return its final hub attitude and position.

Parameters:
  • builder (callable) – buildBSM or buildMujoco.

  • integratorName (str) – integrator attribute name.

  • dt (float) – task time step [s].

  • tol (float) – adaptive tolerance, or None.

Returns:

(sigma_BN, r_BN_N) at the final time – the attitude MRP (shape (3,)) and the hub inertial position [m] (shape (3,)) – or (None, None) if the run diverged.

Return type:

tuple

scenarioCompareParetoRwPanels.hubInertiaBSM()[source]

BSM hub inertia: bare hub plus the three folded-in wheel tensors.

scenarioCompareParetoRwPanels.makeIntegrator(dynObject, integratorName, tol)[source]

Create and attach an integrator, applying the tolerance if adaptive.

Parameters:
  • dynObject – the Spacecraft or MJScene to integrate.

  • integratorName (str) – attribute name in svIntegrators.

  • tol (float) – relative and absolute tolerance for adaptive integrators, or None.

Returns:

the integrator instance (which the caller must keep referenced).

scenarioCompareParetoRwPanels.mujocoModel()[source]

Return the MJCF model: hub, three reaction wheels, two hinged panels.

scenarioCompareParetoRwPanels.normalizedConfiguration(configuration)[source]

Return one named configuration with its executed step recorded.

scenarioCompareParetoRwPanels.normalizedSweepConfigurations(configurations)[source]

Return execution tuples and serializable requested/executed step records.

scenarioCompareParetoRwPanels.panelRootDcm(hingeX)[source]

Return the root-frame DCM that makes both panels extend away from the hub.

scenarioCompareParetoRwPanels.paretoFrontier(rows, errorKey='error')[source]

Return the non-dominated subset (lowest error for a given or lower cost).

A point is Pareto-optimal if no other point has both lower wall-clock time and lower error. The returned list is sorted by increasing wall-clock time.

Parameters:
  • rows (list) – per-configuration dicts with wall and the metric errorKey.

  • errorKey (str) – row key of the error metric to build the frontier over ("error" for attitude, "positionError" for hub position).

Returns:

the non-dominated configurations, sorted by wall-clock time.

Return type:

list

scenarioCompareParetoRwPanels.plotResults(bsmRows, mujocoRows, referenceThreshold=0.0, positionReferenceThreshold=0.0)[source]

Build the Pareto and frontier figures for both attitude and hub-position error.

Parameters:
  • bsmRows (list) – BSM-engine sweep results.

  • mujocoRows (list) – MuJoCo-engine sweep results (possibly empty).

  • referenceThreshold (float) – conservative attitude reference self-consistency threshold [rad], recorded in JSON but not drawn here.

  • positionReferenceThreshold (float) – conservative position reference self-consistency threshold [m], recorded in JSON but not drawn here.

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareParetoRwPanels.principalAngle(sigmaA, sigmaB)[source]

Principal rotation angle between two attitudes given as MRPs [rad].

The angle is computed from the relative MRP as 4*atan(|sigma_rel|), which stays well conditioned down to machine precision, unlike arccos((trace(C)-1)/2), whose argument approaches 1 for small angles and collapses to zero below roughly 1e-8 rad.

scenarioCompareParetoRwPanels.run(showPlots=False, saveJson=False, sweepConfigs=None, reference=None, referenceCheck=None, 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 Pareto data to results/scenarioCompareParetoRwPanels.json. Defaults to False.

  • sweepConfigs (list, optional) – override the integrator sweep (the unit test passes a reduced set). Defaults to SWEEP_CONFIGS.

  • reference (dict, optional) – override the reference (truth) configuration. Defaults to REFERENCE.

  • referenceCheck (dict, optional) – override the reference-accuracy check configuration. Defaults to REFERENCE_CHECK.

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

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareParetoRwPanels.snappedStep(dt)[source]

Snap a requested step onto the comparison horizon and report the change.

scenarioCompareParetoRwPanels.sweepEngine(builder, reference={'dt': 0.5, 'integrator': 'svIntegratorRKF78', 'tol': 1e-13}, referenceCheck={'dt': 0.5, 'integrator': 'svIntegratorRKF78', 'tol': 1e-12}, sweepConfigs=None)[source]

Run the reference and every sweep configuration for one engine.

Parameters:
  • builder (callable) – buildBSM or buildMujoco.

  • reference (dict) – reference (truth) configuration with keys integrator, dt and tol.

  • referenceCheck (dict) – second configuration used to estimate reference self-consistency.

  • sweepConfigs (sequence, optional) – configurations to evaluate. Defaults to SWEEP_CONFIGS.

Returns:

(rows, attitudeCheck, positionCheck) where rows holds one dict per successful configuration (integrator, attitude error, position error, wall-clock) and the final values are the attitude [rad] and position [m] disagreements between the selected reference and check configurations.

Return type:

tuple