Files
differential-equations/roadmap/features/03-rosenbrock23.md
Connor Johnstone e3788bf607 Added the roadmap
2025-10-23 16:47:48 -04:00

325 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Feature: Rosenbrock23 Method
## Overview
Rosenbrock23 is a 2nd/3rd order L-stable Rosenbrock-W method designed for stiff ODEs. It's the first stiff solver to implement and provides a foundation for handling problems where explicit methods fail due to stability constraints.
**Key Characteristics:**
- Order: 2(3) - actually 3rd order solution with 2nd order embedded for error
- Stages: 3
- L-stable: Excellent damping of high-frequency oscillations
- Stiff-aware: Can handle stiffness ratios up to ~10^6
- W-method: Uses approximate Jacobian (doesn't need exact)
- Stiff-aware interpolation: 2nd order dense output
## Why This Feature Matters
- **Stiff problems**: Many real-world ODEs are stiff (chemistry, circuit simulation, etc.)
- **Completes basic toolkit**: With DP5/Tsit5 for non-stiff + Rosenbrock23 for stiff, can handle most problems
- **Foundation for auto-switching**: Enables automatic stiffness detection and algorithm selection
- **Widely used**: MATLAB's ode23s is based on this method
## Dependencies
### Required Infrastructure
- **Linear solver** (see feature #18)
- LU factorization for dense systems
- Generic `LinearSolver` trait
- **Jacobian computation** (see feature #19)
- Finite difference approximation
- User-provided analytical Jacobian (optional)
- Auto-diff integration (future)
### Recommended to Implement First
1. Linear solver infrastructure
2. Jacobian computation
3. Then Rosenbrock23
## Implementation Approach
### Mathematical Background
Rosenbrock methods solve:
```
(I - γh*J) * k_i = h*f(y_n + Σa_ij*k_j) + h*J*Σc_ij*k_j
```
Where:
- J is the Jacobian ∂f/∂y
- γ is a method-specific constant
- Stages k_i are computed by solving linear systems
For Rosenbrock23:
- γ = 1/(2 + √2) ≈ 0.2928932188
- 3 stages requiring 3 linear solves per step
- W-method: J can be approximate or outdated
### Algorithm Structure
```rust
struct Rosenbrock23<D> {
a_tol: SVector<f64, D>,
r_tol: f64,
// Tableau coefficients (as constants)
// Linear solver (to be injected or created)
}
```
### Step Procedure
1. Compute or reuse Jacobian J = ∂f/∂y(t_n, y_n)
2. Form W = I - γh*J
3. Factor W (LU decomposition)
4. For each stage i=1,2,3:
- Compute RHS based on previous stages
- Solve W*k_i = RHS
5. Compute solution: y_{n+1} = y_n + b1*k1 + b2*k2 + b3*k3
6. Compute error: err = e1*k1 + e2*k2 + e3*k3
7. Store dense output coefficients
### Tableau Coefficients
From Shampine & Reichelt (1997) - MATLAB's ode23s:
```
γ = 1/(2 + √2)
Stage matrix for ki calculations:
a21 = 1.0
a31 = 1.0
a32 = 0.0
c21 = -1.0707963267948966
c31 = -0.31381995116890154
c32 = 1.3846153846153846
Solution weights:
b1 = 0.5
b2 = 0.5
b3 = 0.0
Error estimate:
d1 = -0.17094382871185335
d2 = 0.17094382871185335
d3 = 0.0
```
### Jacobian Management
Key decisions:
- **When to update J**: Error signal, step rejection, every N steps
- **Finite difference formula**: Forward or central differences
- **Sparsity**: Dense for now, sparse in future
- **Storage**: Cache J and LU factorization
### Linear Solver Integration
```rust
trait LinearSolver<D> {
fn factor(&mut self, matrix: &SMatrix<f64, D, D>) -> Result<(), Error>;
fn solve(&self, rhs: &SVector<f64, D>) -> Result<SVector<f64, D>, Error>;
}
struct DenseLU<D> {
lu: SMatrix<f64, D, D>,
pivots: [usize; D],
}
```
## Implementation Tasks
### Infrastructure (Prerequisites)
- [ ] **Linear solver trait and implementation**
- [ ] Define `LinearSolver` trait
- [ ] Implement dense LU factorization
- [ ] Add solve method
- [ ] Tests for random matrices
- [ ] **Jacobian computation**
- [ ] Forward finite differences: J[i,j] ≈ (f(y + ε*e_j) - f(y)) / ε
- [ ] Epsilon selection (√machine_epsilon * max(|y[j]|, 1))
- [ ] Cache for function evaluations
- [ ] Test on known Jacobians
### Core Algorithm
- [ ] Define `Rosenbrock23` struct
- [ ] Tableau constants
- [ ] Tolerance fields
- [ ] Jacobian update strategy fields
- [ ] Linear solver instance
- [ ] Implement `step()` method
- [ ] Decide if Jacobian update needed
- [ ] Compute J if needed
- [ ] Form W = I - γh*J
- [ ] Factor W
- [ ] Stage 1: Solve for k1
- [ ] Stage 2: Solve for k2
- [ ] Stage 3: Solve for k3
- [ ] Combine for solution
- [ ] Compute error estimate
- [ ] Return (y_next, error, dense_coeffs)
- [ ] Implement `interpolate()` method
- [ ] 2nd order stiff-aware interpolation
- [ ] Uses k1, k2, k3
- [ ] Jacobian update strategy
- [ ] Update on first step
- [ ] Update on step rejection
- [ ] Update if error test suggests (heuristic)
- [ ] Reuse otherwise
- [ ] Implement constants
- [ ] `ORDER = 3`
- [ ] `STAGES = 3`
- [ ] `ADAPTIVE = true`
- [ ] `DENSE = true`
### Integration
- [ ] Add to prelude
- [ ] Module exports
- [ ] Builder pattern for configuration
### Testing
- [ ] **Stiff test: Van der Pol oscillator**
- [ ] μ = 1000 (very stiff)
- [ ] Explicit methods would need 100000+ steps
- [ ] Rosenbrock23 should handle in <1000 steps
- [ ] Verify solution accuracy
- [ ] **Stiff test: Robertson problem**
- [ ] Classic stiff chemistry problem
- [ ] 3 equations, stiffness ratio ~10^11
- [ ] Verify conservation properties
- [ ] Compare to reference solution
- [ ] **L-stability test**
- [ ] Verify method damps oscillations
- [ ] Test problem with large negative eigenvalues
- [ ] Should remain stable with large time steps
- [ ] **Convergence test**
- [ ] Verify 3rd order convergence on smooth problem
- [ ] Use linear test problem
- [ ] Check error scales as h^3
- [ ] **Jacobian update strategy test**
- [ ] Count Jacobian evaluations
- [ ] Verify not recomputing unnecessarily
- [ ] Verify updates when needed
- [ ] **Comparison test**
- [ ] Same stiff problem with explicit method (DP5)
- [ ] DP5 should require far more steps or fail
- [ ] Rosenbrock23 should be efficient
### Benchmarking
- [ ] Van der Pol benchmark (μ = 1000)
- [ ] Robertson problem benchmark
- [ ] Compare to Julia implementation performance
### Documentation
- [ ] Docstring explaining Rosenbrock methods
- [ ] When to use vs explicit methods
- [ ] Stiffness indicators
- [ ] Example with stiff problem
- [ ] Notes on Jacobian strategy
## Testing Requirements
### Van der Pol Oscillator
```rust
// y1' = y2
// y2' = μ(1 - y1²)y2 - y1
// Initial: y1(0) = 2, y2(0) = 0
// μ = 1000 (very stiff)
```
Integrate from t=0 to t=2000.
Expected behavior:
- Explicit method: >100,000 steps or fails
- Rosenbrock23: ~500-2000 steps depending on tolerance
- Should track limit cycle accurately
### Robertson Problem
```rust
// y1' = -0.04*y1 + 1e4*y2*y3
// y2' = 0.04*y1 - 1e4*y2*y3 - 3e7*y2²
// y3' = 3e7*y2²
// Conservation: y1 + y2 + y3 = 1
```
Integrate from t=0 to t=1e11 (log scale output)
Verify:
- Conservation law maintained
- Correct steady-state behavior
- Handles extreme stiffness ratio
## References
1. **Original Method**:
- Shampine, L.F. and Reichelt, M.W. (1997)
- "The MATLAB ODE Suite", SIAM J. Sci. Computing, 18(1), 1-22
- DOI: 10.1137/S1064827594276424
2. **Rosenbrock Methods Theory**:
- Hairer, E. and Wanner, G. (1996)
- "Solving Ordinary Differential Equations II: Stiff and DAE Problems"
- Chapter IV.7
3. **Julia Implementation**:
- `OrdinaryDiffEq.jl/lib/OrdinaryDiffEqRosenbrock/`
- Files: `rosenbrock_perform_step.jl`, `rosenbrock_caches.jl`
4. **W-methods**:
- Steihaug, T. and Wolfbrandt, A. (1979)
- "An attempt to avoid exact Jacobian and nonlinear equations in the numerical solution of stiff differential equations"
- Math. Comp., 33, 521-534
## Complexity Estimate
**Effort**: Large (20-30 hours)
- Linear solver: 8-10 hours
- Jacobian computation: 4-6 hours
- Rosenbrock23 core: 6-8 hours
- Testing and debugging: 6-8 hours
**Risk**: High
- First implicit method - new complexity
- Linear algebra integration
- Numerical stability issues possible
- Jacobian update strategy tuning needed
## Success Criteria
- [ ] Solves Van der Pol (μ=1000) efficiently
- [ ] Solves Robertson problem accurately
- [ ] Demonstrates L-stability
- [ ] Convergence test shows 3rd order
- [ ] Outperforms explicit methods on stiff problems by 10-100x in steps
- [ ] Jacobian reuse strategy effective (not recomputing every step)
- [ ] Documentation complete with stiff problem examples
- [ ] Performance within 2x of Julia implementation
## Future Enhancements
- [ ] User-provided analytical Jacobians
- [ ] Sparse Jacobian support
- [ ] More sophisticated update strategies
- [ ] Rodas4, Rodas5P (higher-order Rosenbrock methods)
- [ ] Krylov linear solvers for large systems