differential-equations 0.6.1

A Rust library for solving differential equations.
Documentation
# Boundary Value Problems (BVP)

Boundary value problems solve differential equations with constraints at both
ends of the interval. The `BVP` builder mirrors the `IVP` builder style, but it
uses boundary residuals instead of fixed initial conditions.

For ODE BVPs, define the differential equation with the regular `ODE` trait and
define the endpoint residual with `Boundary`. The same equation type can be used
for IVP solves with `IVP::ode` and BVP solves with `BVP::ode` when it implements
both traits.

## Defining an ODE BVP

The `Boundary` trait receives the state at the left endpoint (`y_a`), the state
at the right endpoint (`y_b`), and writes a residual into `res`. A BVP is solved
when every residual component is zero.

```rust
use differential_equations::prelude::*;

struct HarmonicOscillator;

impl ODE<f64, [f64; 2]> for HarmonicOscillator {
    fn diff(&self, _t: f64, y: &[f64; 2], dydt: &mut [f64; 2]) {
        dydt[0] = y[1];
        dydt[1] = -y[0];
    }
}

impl Boundary<f64, [f64; 2]> for HarmonicOscillator {
    fn boundary(&self, y_a: &[f64; 2], y_b: &[f64; 2], res: &mut [f64; 2]) {
        res[0] = y_a[0];
        res[1] = y_b[0] - 1.0;
    }
}

let problem = HarmonicOscillator;
let method = Shooting::single(ExplicitRungeKutta::dop853());
let solution = BVP::ode(
    &problem,
    0.0,
    std::f64::consts::FRAC_PI_2,
    [0.0, 0.5],
)
.method(method)
.solve()?;
# Ok::<(), differential_equations::error::Error<f64, [f64; 2]>>(())
```

## Closure-Based Setup

For closure-based setup, use `BVP::ode_from_fn`:

```rust
use differential_equations::prelude::*;

let method = Shooting::single(ExplicitRungeKutta::dop853());
let solution = BVP::ode_from_fn(
    |_t, y: &[f64; 2], dydt: &mut [f64; 2]| {
        dydt[0] = y[1];
        dydt[1] = -y[0];
    },
    |y_a: &[f64; 2], y_b: &[f64; 2], res: &mut [f64; 2]| {
        res[0] = y_a[0];
        res[1] = y_b[0] - 1.0;
    },
    0.0,
    std::f64::consts::FRAC_PI_2,
    [0.0, 0.5],
)
.method(method)
.solve()?;
# Ok::<(), differential_equations::error::Error<f64, [f64; 2]>>(())
```

## Pipe Heat Transfer Example

The ODE examples include a steady pipe heat-transfer BVP:

```text
T'' = beta^2 (T - T_ambient)
T(0) = T_inlet
dT/dx(L) = 0
```

The first-order state is `[T, dT/dx]`; `Boundary` fixes the inlet temperature and
the insulated outlet gradient while `Shooting` finds the initial temperature
gradient.
See [Pipe Heat Transfer](../examples/ode/18_pipe_heat_transfer/main.rs).

## Shooting Methods

`Shooting::single` solves ODE BVPs by repeatedly solving one IVP across the full
interval and applying Newton iteration to the guessed initial state.

```rust
let method = Shooting::single(ExplicitRungeKutta::dop853())
    .tolerance(1e-8)
    .max_iterations(50);
```

`Shooting::multiple` partitions the interval into subintervals, solves an IVP on
each segment, and uses Newton iteration to satisfy both the endpoint boundary
conditions and continuity between neighboring segment states.

```rust
let method = Shooting::multiple(ExplicitRungeKutta::dop853())
    .segments(5)
    .tolerance(1e-8)
    .max_iterations(50);
```

For both methods, the boundary residual state must have the same dimension as
the ODE state.

## Output and Statistics

`BVP` supports the same output controls as `IVP` for the final converged ODE
trajectory:

```rust
let solution = BVP::ode(&problem, 0.0, 1.0, [0.0, 0.0])
    .t_eval([0.0, 0.25, 0.5, 0.75, 1.0])
    .method(Shooting::single(
        ExplicitRungeKutta::dop853().rtol(1e-8).atol(1e-10),
    ))
    .solve()?;
# Ok::<(), differential_equations::error::Error<f64, [f64; 2]>>(())
```

Available output options include `solout`, `even`, `dense`, `t_eval`, `event`,
`crossing`, and `hyperplane_crossing`. For shooting methods, these output
controls are applied after the boundary residual has converged, so the returned
points describe the final trajectory. The returned `Solution` also includes the
function evaluations, finite-difference Jacobian evaluations, Newton iterations,
linear decompositions, solves, accepted/rejected IVP steps, and elapsed wall time
used by the shooting solve.

## API Summary

| Item | Purpose |
|---|---|
| `BVP::ode` | Build an ODE boundary value problem from a type implementing `ODE + Boundary`. |
| `BVP::ode_from_fn` | Build an ODE boundary value problem from derivative and boundary closures. |
| `Boundary` | Define the endpoint residual for a BVP. |
| `Shooting::single` | Solve ODE BVPs by iterating on the unknown initial state. |
| `Shooting::multiple` | Solve ODE BVPs by iterating on segment node states and continuity residuals. |
| `BVP::t_eval`, `BVP::even`, `BVP::dense` | Select output points for the final converged trajectory. |