ODE Solver Error Control · Issue #160 · pathsim/pathsim · GitHub
Skip to content

ODE Solver Error Control #160

Open
Open

Description

@milanofthe

The adaptive timestep solvers currently use a P controler to adjust the timestep given an estimate for the current truncation error. In the literature and in practice, different kinds of controlers have been explored for that such as I, PI and PID controlers.

It would make sense to implement a new class TruncationErrorControler to modularize this and enable different controler types.

Activity

  1. added
    enhancementNew feature or request
    numericsnumerical solvers
    roadmapThis label identifies issues that are development roadmap items for PathSim
    on Dec 2, 2025
  2. miguelpi314 commented on Jul 4, 2026

    @miguelpi314

    Hi @milanofthe, I'd like to take this on. Before implementing, here's the design I'm proposing — happy to adjust based on your input.

    Current state: the P-controller logic is currently duplicated 4 times (ExplicitRungeKutta.error_controller, DiagonallyImplicitRungeKutta.error_controller in _rungekutta.py, and two variants in gear.py), each computing scale = beta / error_norm**(1/(min(m,n)+1)), clipped to [SOL_SCALE_MIN, SOL_SCALE_MAX].

    Proposed design:

    • New module solvers/_stepcontrol.py with a small class hierarchy: a base StepController (or should it be TruncationErrorController — note the issue title has a typo, "Controler", happy to go either way) exposing update(error_norm, order) -> scale, plus PController (wraps existing behavior exactly, becomes the default so results don't change for anyone), PIController, and possibly PIDController following Söderlind's digital-filter formulation ("Digital Filters in Adaptive Time-Stepping", 2003).
    • Composition, not inheritance: each solver (ExplicitRungeKutta, DiagonallyImplicitRungeKutta, GEAR, BDF) holds a self._step_controller instance instead of reimplementing the scale formula. The controller owns whatever state it needs (e.g. previous error norm(s) for PI/PID) and gets reset alongside revert().
    • Backward compatibility: default controller stays PController with the current beta=0.9, so no existing test or simulation output changes unless a user opts into a different controller.
    • Open question for you: should the controller type be user-configurable (e.g. RKF45(..., controller='PI')), or is this purely an internal refactor for now with PI/PID added as a later step?

    Let me know if this direction makes sense before I start implementing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestnumericsnumerical solversrefactorroadmapThis label identifies issues that are development roadmap items for PathSim

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions