ERKStep

The ERKStep factory wraps a configurable explicit Runge–Kutta integrator. It accepts any ERKTableau and ships with adaptive integral step-control defaults. The factory performs staged right-hand-side evaluations on the GPU and supports optional driver and observable callbacks.

Defaults

algorithm="erk" integrates with the dormand-prince-54 tableau — explicit Dormand–Prince 5(4), seven stages, with an embedded fourth-order error estimate — under adaptive integral control (integral_gain=1.2, safety=0.9, step-size growth clamped to 0.2–10.0×). dopri54, rk45, and ode45 are aliases for the same scheme; the other named schemes in the ERK tableau registry resolve to this class too, falling back to fixed-step control when a tableau has no error estimate (Default settings). Explicit methods need no nonlinear or linear solver.

class cubie.integrators.algorithms.ERKStep(precision: type[float16] | type[float32] | type[float64] | dtype[float16] | dtype[float32] | dtype[float64], n_states: int, dxdt_fn: Callable | None = None, observables_fn: Callable | None = None, drivers_fn: Callable | None = None, get_solver_helper_fn: Callable | None = None, tableau: ERKTableau = ERKTableau(a=((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.075, 0.225, 0.0, 0.0, 0.0, 0.0, 0.0), (0.9777777777777777, -3.7333333333333334, 3.5555555555555554, 0.0, 0.0, 0.0, 0.0), (2.9525986892242035, -11.595793324188385, 9.822892851699436, -0.2908093278463649, 0.0, 0.0, 0.0), (2.8462752525252526, -10.757575757575758, 8.906422717743473, 0.2784090909090909, -0.2735313036020583, 0.0, 0.0), (0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0)), b=(0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0), c=(0.0, 0.2, 0.3, 0.8, 0.8888888888888888, 1.0, 1.0), order=5, b_hat=(0.08991319444444444, 0.0, 0.4534890685834082, 0.6140625, -0.2715123820754717, 0.08904761904761904, 0.025), embedded_order=4, dense_prediction_ratio_float16=0.0, dense_prediction_ratio_float32=0.0, dense_prediction_ratio_float64=0.0, defaults={}), n_drivers: int = 0, **kwargs)[source]

Bases: ODEExplicitStep

Generic explicit Runge–Kutta step with configurable tableaus.

__init__(precision: type[float16] | type[float32] | type[float64] | dtype[float16] | dtype[float32] | dtype[float64], n_states: int, dxdt_fn: Callable | None = None, observables_fn: Callable | None = None, drivers_fn: Callable | None = None, get_solver_helper_fn: Callable | None = None, tableau: ERKTableau = ERKTableau(a=((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.075, 0.225, 0.0, 0.0, 0.0, 0.0, 0.0), (0.9777777777777777, -3.7333333333333334, 3.5555555555555554, 0.0, 0.0, 0.0, 0.0), (2.9525986892242035, -11.595793324188385, 9.822892851699436, -0.2908093278463649, 0.0, 0.0, 0.0), (2.8462752525252526, -10.757575757575758, 8.906422717743473, 0.2784090909090909, -0.2735313036020583, 0.0, 0.0), (0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0)), b=(0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0), c=(0.0, 0.2, 0.3, 0.8, 0.8888888888888888, 1.0, 1.0), order=5, b_hat=(0.08991319444444444, 0.0, 0.4534890685834082, 0.6140625, -0.2715123820754717, 0.08904761904761904, 0.025), embedded_order=4, dense_prediction_ratio_float16=0.0, dense_prediction_ratio_float32=0.0, dense_prediction_ratio_float64=0.0, defaults={}), n_drivers: int = 0, **kwargs) None[source]

Initialise the Runge–Kutta step configuration.

This constructor creates an ERK step object and automatically selects appropriate default step controller settings based on whether the tableau has an embedded error estimate. Tableaus with error estimates default to adaptive stepping (integral controller), while errorless tableaus default to fixed stepping.

Parameters:
  • precision – Floating-point precision for CUDA computations (np.float32 or np.float64).

  • n_states – Number of state variables in the ODE system.

  • dxdt_fn – Compiled CUDA device function computing state derivatives. Should match signature expected by the integration kernel.

  • observables_fn – Optional compiled CUDA device function computing observable quantities from the state.

  • drivers_fn – Optional compiled CUDA device function computing time-varying driver inputs.

  • get_solver_helper_fn – Factory function returning solver helper for implicit stages (not used in explicit methods but included for interface consistency).

  • tableau – Explicit Runge–Kutta tableau describing the coefficients used by the integrator. Defaults to DEFAULT_ERK_TABLEAU (Dormand-Prince 5(4)).

  • n_drivers – Number of driver variables in the system.

  • **kwargs – Optional parameters passed to config classes. See ERKStepConfig for available parameters. None values are ignored.

Notes

The step controller defaults are selected dynamically:

  • If tableau.has_error_estimate is True: Uses ERK_ADAPTIVE_DEFAULTS (integral controller)

  • If tableau.has_error_estimate is False: Uses ERK_FIXED_DEFAULTS (fixed-step controller)

This automatic selection prevents incompatible configurations where an adaptive controller is paired with an errorless tableau. Users can still override these defaults by explicitly specifying step controller settings when creating a Solver or calling solve_ivp().

Examples

Create an ERK step with the default Dormand-Prince tableau:

>>> from cubie.integrators.algorithms.generic_erk import ERKStep
>>> import numpy as np
>>> step = ERKStep(precision=np.float32,n_states=3)
>>> step.algorithm_defaults["step_controller"]
'i'

Create an ERK step with Classical RK4 (errorless):

>>> from cubie.integrators.algorithms.generic_erk_tableaus import (
...     CLASSICAL_RK4_TABLEAU
... )
>>> step = ERKStep(
...     precision=np.float32, n_states=3, tableau=CLASSICAL_RK4_TABLEAU
... )
>>> step.algorithm_defaults["step_controller"]
'fixed'
build_step(dxdt_fn: Callable, observables_fn: Callable, drivers_fn: Callable | None, numba_precision: type, n: int, n_drivers: int) StepCache[source]

Compile the explicit Runge–Kutta device step.

default_tableau = ERKTableau(a=((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.075, 0.225, 0.0, 0.0, 0.0, 0.0, 0.0), (0.9777777777777777, -3.7333333333333334, 3.5555555555555554, 0.0, 0.0, 0.0, 0.0), (2.9525986892242035, -11.595793324188385, 9.822892851699436, -0.2908093278463649, 0.0, 0.0, 0.0), (2.8462752525252526, -10.757575757575758, 8.906422717743473, 0.2784090909090909, -0.2735313036020583, 0.0, 0.0), (0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0)), b=(0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0), c=(0.0, 0.2, 0.3, 0.8, 0.8888888888888888, 1.0, 1.0), order=5, b_hat=(0.08991319444444444, 0.0, 0.4534890685834082, 0.6140625, -0.2715123820754717, 0.08904761904761904, 0.025), embedded_order=4, dense_prediction_ratio_float16=0.0, dense_prediction_ratio_float32=0.0, dense_prediction_ratio_float64=0.0, defaults={})

Tableau a bare family alias builds on; None for fixed schemes.

classmethod family_defaults(tableau=None) AlgorithmDefaults[source]

Adaptive or fixed defaults by the tableau’s error estimate.

property has_error_estimate: bool

Return True if the tableau supplies an error estimate.

property is_multistage: bool

Return True when the method has multiple stages.

property optimisation_candidates: Tuple[Dict[str, Any], ...]

other_small unrolling crossed with state placement, plus a shared stage_rhs at full unrolling.

property order: int

Return the classical order of accuracy.

performance_defaults(hardware: Any = None) Dict[str, Any][source]

Share a spilling accumulating state while the GPU stays full.

register_buffers() None[source]

Register buffers with buffer_registry.

property threads_per_step: int

Return the number of CUDA threads that advance one state.

class cubie.integrators.algorithms.generic_erk.ERKStepConfig(precision: type[float16] | type[float32] | type[float64] | dtype[float16] | dtype[float32] | dtype[float64], n_states: int = 1, n_drivers: int = 0, is_adaptive: bool = True, dxdt_fn: Callable | None = None, observables_fn: Callable | None = None, drivers_fn: Callable | None = None, get_solver_helper_fn: Callable | None = None, tableau: ERKTableau = ERKTableau(a=((0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.075, 0.225, 0.0, 0.0, 0.0, 0.0, 0.0), (0.9777777777777777, -3.7333333333333334, 3.5555555555555554, 0.0, 0.0, 0.0, 0.0), (2.9525986892242035, -11.595793324188385, 9.822892851699436, -0.2908093278463649, 0.0, 0.0, 0.0), (2.8462752525252526, -10.757575757575758, 8.906422717743473, 0.2784090909090909, -0.2735313036020583, 0.0, 0.0), (0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0)), b=(0.09114583333333333, 0.0, 0.44923629829290207, 0.6510416666666666, -0.322376179245283, 0.13095238095238096, 0.0), c=(0.0, 0.2, 0.3, 0.8, 0.8888888888888888, 1.0, 1.0), order=5, b_hat=(0.08991319444444444, 0.0, 0.4534890685834082, 0.6140625, -0.2715123820754717, 0.08904761904761904, 0.025), embedded_order=4, dense_prediction_ratio_float16=0.0, dense_prediction_ratio_float32=0.0, dense_prediction_ratio_float64=0.0, defaults={}), stage_rhs_location: str = 'local', stage_accumulator_location: str = 'local', *, jit_flags: JITFlags = NOTHING, unroll: UnrollFlags = NOTHING)[source]

Bases: ExplicitStepConfig

Configuration describing an explicit Runge–Kutta integrator.

Parameters:
property first_same_as_last: bool

Return True when the tableau shares the first and last stage.

stage_accumulator_location: str
stage_rhs_location: str
tableau: ERKTableau