differential-equations 0.5.3

A Rust library for solving differential equations.
Documentation
# Architecture

This library's core design philosophy is **trait-driven design**. Components are defined as traits, allowing for multiple implementations that share a common interface. This approach centralizes solver functionality, promoting DRY (Don't Repeat Yourself) principles and reducing potential bugs. Unlike traditional C/Fortran implementations where each solver duplicates functionalities like event handling and output control, this trait-driven design consolidates these common features. This not only minimizes code duplication but also simplifies the development of new solvers, as they only need to implement solver-specific logic.

The library's components are organized into four main categories:

- **Solver Controller**: This central component orchestrates the solving process. It utilizes a chosen numerical method to step through the problem, tracks statistics, manages events, and invokes the user-provided `solout` (solution output) function between steps. For Ordinary Differential Equations (ODEs), the `solve_ode` function serves this role. To manage the complexity of generics, it's often abstracted via structs like `ODEProblem`, which simplifies solving ODEs by implicitly assigning generic types.

- **Numerical Methods**: These components define the initialization and step functions for a given solver. Each numerical method is encapsulated in a struct that holds its state, enabling the solver controller to manage various differential solvers. Importantly, all numerical methods also implement an interpolation trait. This separation allows `solout` functions to access solver state for interpolation purposes in a controlled manner.

- **Differential Equation Definition**: This component represents the differential equation to be solved, defined by a user-implemented trait. Using a struct to define the differential equation allows for easy duplication of constants with different initial conditions. Users can choose the floating-point precision (`f32` or `f64`) and state representation (e.g., `f32`, `f64`, `nalgebra::SVector`, or custom structs with generic `T` fields via the derive `State` macro). This flexibility allows users to tailor the library to their specific needs. The respective differential equation implementor traits (e.g., `ODE`, `DDE`) also support optional event and jacobian functions. Implementing these can define termination events or enhance the performance of implicit solvers.

- **Solution Output (`solout`)**: The `Solout` trait defines how solution points are handled and can be implemented by the user. More commonly, pre-built implementations are available and integrated into solver abstractions like `ODEProblem` and `DDEProblem`. Common implementations include:
    * `even`: Output at evenly spaced time points.
    * `dense`: Output at every solver step.
    * `crossing`: Output when a specific event function crosses zero.
    * `t_eval`: Output at user-specified time points.
    The desired output points are determined using the interpolation trait implemented by the solvers. Custom `solout` implementations also allow users to perform intermediate tasks, such as updating plots, writing to files, or calculating and storing system properties (e.g., energy).

## Event Handling

The library supports two primary types of event handling:

1.  **Differential Equation Event Function**:
    * Implemented as part of the differential equation trait.
    * Receives the current time and state, returning a control flag (e.g., continue or terminate).
    * If termination is requested, a root-finding algorithm is employed to precisely locate the event time.
    * **Use Case**: Ideal for basic event detection, such as checking if states go out of a predefined range, without needing a custom `solout` function.
    * **Limitation**: Provides only the current time and state.

2.  **`Solout` Function Control Flag**:
    * The `solout` function itself can return a control flag to stop the integration.
    * Instead of iterative root-finding for the event point, the `solout` function is expected to use the provided interpolation capabilities to log the final state if needed.
    * **Use Case**: Offers more flexibility for complex event handling and allows for custom actions upon event detection.
    * **Consideration**: Requires more implementation effort compared to the simpler event function.

In summary, the differential equation's event function is simpler for straightforward termination conditions, while the `solout` function provides greater flexibility for more complex event logic and actions.