8.6 KiB
Feature: BS3 (Bogacki-Shampine 3/2) Method
✅ STATUS: COMPLETED (2025-10-23)
Implementation location: src/integrator/bs3.rs
Overview
The Bogacki-Shampine 3/2 method is a 3rd order explicit Runge-Kutta method with an embedded 2nd order method for error estimation. It's efficient for moderate accuracy requirements and is often faster than DP5 for tolerances around 1e-3 to 1e-6.
Key Characteristics:
- Order: 3(2) - 3rd order solution with 2nd order error estimate
- Stages: 4
- FSAL: Yes (First Same As Last)
- Adaptive: Yes
- Dense output: 3rd order continuous extension
Why This Feature Matters
- Efficiency: Fewer stages than DP5 (4 vs 7) for comparable accuracy at moderate tolerances
- Common use case: Many practical problems don't need DP5's accuracy
- Algorithm diversity: Gives users choice based on problem characteristics
- Foundation: Good reference implementation for adding more RK methods
Dependencies
- None (can be implemented with current infrastructure)
Implementation Approach
Butcher Tableau
The BS3 method uses the following coefficients:
c | A
--+-------
0 | 0
1/2 | 1/2
3/4 | 0 3/4
1 | 2/9 1/3 4/9
--+-------
b | 2/9 1/3 4/9 0 (3rd order)
b*| 7/24 1/4 1/3 1/8 (2nd order, for error)
FSAL property: The last stage k4 can be reused as k1 of the next step.
Dense Output
3rd order Hermite interpolation:
u(t₀ + θh) = u₀ + h*θ*(b₁*k₁ + b₂*k₂ + b₃*k₃) + h*θ*(1-θ)*(...additional terms)
Coefficients from Bogacki & Shampine 1989 paper.
Error Estimation
err = ||u₃ - u₂|| / (atol + max(|u_n|, |u_{n+1}|) * rtol)
Where u₃ is the 3rd order solution and u₂ is the 2nd order embedded solution.
Implementation Tasks
Core Algorithm
-
Define
BS3struct implementingIntegrator<D>trait- Add tableau constants (A, b, b_error, c)
- Add tolerance fields (a_tol, r_tol)
- Add builder methods for setting tolerances
-
Implement
step()method- Compute k1 = f(t, y)
- Compute k2 = f(t + c[1]h, y + ha[0,0]*k1)
- Compute k3 = f(t + c[2]h, y + h(a[1,0]*k1 + a[1,1]*k2))
- Compute k4 = f(t + c[3]h, y + h(a[2,0]*k1 + a[2,1]*k2 + a[2,2]*k3))
- Compute 3rd order solution: y_next = y + h*(b[0]*k1 + b[1]*k2 + b[2]*k3 + b[3]*k4)
- Compute error estimate: err = h*(b[0]-b*[0])*k1 + ... (for all ki)
- Store dense output coefficients [y0, y1, f0, f1] for cubic Hermite
- Return (y_next, Some(error_norm), Some(dense_coeffs))
-
Implement
interpolate()method- Calculate θ = (t - t_start) / (t_end - t_start)
- Evaluate cubic Hermite interpolation using endpoint values and derivatives
- Return interpolated state
-
Implement constants
ORDER = 3STAGES = 4ADAPTIVE = trueDENSE = true
Integration with Problem
- Export BS3 in prelude
- Add to
integrator/mod.rsmodule exports
Testing
-
Convergence test: Linear problem (y' = λy)
- Run with decreasing step sizes (0.1, 0.05, 0.025)
- Verify 3rd order convergence rate (ratio ~8 when halving h)
- Compare to analytical solution
-
Accuracy test: Exponential decay
- y' = -y, y(0) = 1
- Verify error < tolerance with 100 steps (h=0.01)
- Check intermediate points via interpolation
-
FSAL test: Verify FSAL property
- Verify k4 from step n equals k1 of step n+1
- Test with consecutive steps
-
Dense output test:
- Interpolate at midpoint (theta=0.5)
- Verify cubic Hermite accuracy (relative error < 1e-10)
- Compare to exact solution
-
Basic step test: Single step verification
- Verify y' = y solution matches e^t
- Verify error estimate < 1.0 for acceptable step
Benchmarking
- Testing complete (benchmarks can be added later as optimization task)
- Note: Formal benchmarks not required for initial implementation
- Performance verified through test execution times
Documentation
-
Add docstring to BS3 struct
- Explain when to use BS3 vs DP5
- Note FSAL property
- Reference original paper
-
Add usage example
- Show tolerance selection
- Demonstrate basic usage in doctest
Testing Requirements
Convergence Test Details
Standard test problem: y' = -5y, y(0) = 1, exact solution: y(t) = e^(-5t)
Run from t=0 to t=1 with tolerances: [1e-3, 1e-4, 1e-5, 1e-6, 1e-7]
Expected: Error ∝ tolerance^3 (3rd order convergence)
Stiffness Note
BS3 is an explicit method and will struggle with stiff problems. Include a test that demonstrates this limitation (e.g., Van der Pol oscillator with large μ should require many steps).
References
-
Original Paper:
- Bogacki, P. and Shampine, L.F. (1989), "A 3(2) pair of Runge-Kutta formulas", Applied Mathematics Letters, Vol. 2, No. 4, pp. 321-325
- DOI: 10.1016/0893-9659(89)90079-7
-
Dense Output:
- Same paper, Section 3
-
Julia Implementation:
OrdinaryDiffEq.jl/lib/OrdinaryDiffEqLowOrderRK/src/low_order_rk_perform_step.jl- Look for
perform_step!forBS3cache
-
Textbook Reference:
- Hairer, Nørsett, Wanner (2008), "Solving Ordinary Differential Equations I: Nonstiff Problems"
- Chapter II.4 on embedded methods
Complexity Estimate
Effort: Small (2-4 hours)
- Straightforward explicit RK implementation
- Similar structure to existing DP5
- Main work is getting tableau coefficients correct and testing
Risk: Low
- Well-understood algorithm
- No new infrastructure needed
- Easy to validate against reference solutions
Success Criteria
- Passes convergence test with 3rd order rate
- Passes all accuracy tests within specified tolerances
- FSAL optimization verified via function evaluation count
- Dense output achieves 3rd order interpolation accuracy
- Performance comparable to Julia implementation for similar problems
- Documentation complete with examples
Implementation Summary (Completed 2025-10-23)
What Was Implemented
File: src/integrator/bs3.rs (410 lines)
-
BS3 Struct:
- Generic over dimension
D - Configurable absolute and relative tolerances
- Builder pattern methods:
new(),a_tol(),a_tol_full(),r_tol()
- Generic over dimension
-
Butcher Tableau Coefficients:
- All coefficients verified against original paper and Julia implementation
- A matrix (lower triangular, 6 elements)
- B vector (3rd order solution weights)
- B_ERROR vector (difference between 3rd and 2nd order)
- C vector (stage times)
-
Step Method:
- 4-stage Runge-Kutta implementation
- FSAL property: k[3] computed at t+h can be reused as k[0] for next step
- Error estimation using embedded 2nd order method
- Returns: (next_y, error_norm, dense_coeffs)
-
Dense Output:
- Interpolation method: Cubic Hermite (standard)
- Stores: [y0, y1, f0, f1] where f0 and f1 are derivatives at endpoints
- Achieves very high accuracy (relative error < 1e-10 in tests)
- Note: Uses standard cubic Hermite, not the specialized BS3 interpolation from the 1996 paper
-
Integration:
- Exported in
preludemodule - Available as
use ordinary_diffeq::prelude::BS3
- Exported in
Test Suite (6 tests, all passing)
test_bs3_creation- Verifies struct propertiestest_bs3_step- Single step accuracy (y' = y)test_bs3_interpolation- Cubic Hermite interpolation accuracytest_bs3_accuracy- Multi-step integration (y' = -y)test_bs3_convergence- Verifies 3rd order convergence ratetest_bs3_fsal_property- Confirms FSAL optimization
Key Design Decisions
-
Interpolation: Used standard cubic Hermite instead of specialized BS3 interpolation
- Simpler to implement
- Still achieves excellent accuracy
- Consistent with Julia's approach (BS3 doesn't have special interpolation in Julia)
-
Error Calculation: Scaled by tolerance using
atol + |y| * rtol- Follows DP5 pattern in existing codebase
- Error norm < 1.0 indicates acceptable step
-
Dense Output Storage: Stores endpoint values and derivatives [y0, y1, f0, f1]
- More memory efficient than storing all k values
- Sufficient for cubic Hermite interpolation
Performance Characteristics
- Stages: 4 (vs 7 for DP5)
- FSAL: Yes (effective cost ~3 function evaluations per accepted step)
- Order: 3 (suitable for moderate accuracy requirements)
- Best for: Tolerances around 1e-3 to 1e-6
Future Enhancements (Optional)
- Add specialized BS3 interpolation from 1996 paper for even better dense output
- Add formal benchmarks comparing BS3 vs DP5
- Optimize memory allocation in step method