diff options
Diffstat (limited to 'packages/hmatrix/src/Numeric/GSL/ODE.hs')
-rw-r--r-- | packages/hmatrix/src/Numeric/GSL/ODE.hs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/packages/hmatrix/src/Numeric/GSL/ODE.hs b/packages/hmatrix/src/Numeric/GSL/ODE.hs new file mode 100644 index 0000000..9a29085 --- /dev/null +++ b/packages/hmatrix/src/Numeric/GSL/ODE.hs | |||
@@ -0,0 +1,138 @@ | |||
1 | {- | | ||
2 | Module : Numeric.GSL.ODE | ||
3 | Copyright : (c) Alberto Ruiz 2010 | ||
4 | License : GPL | ||
5 | |||
6 | Maintainer : Alberto Ruiz (aruiz at um dot es) | ||
7 | Stability : provisional | ||
8 | Portability : uses ffi | ||
9 | |||
10 | Solution of ordinary differential equation (ODE) initial value problems. | ||
11 | |||
12 | <http://www.gnu.org/software/gsl/manual/html_node/Ordinary-Differential-Equations.html> | ||
13 | |||
14 | A simple example: | ||
15 | |||
16 | @ | ||
17 | import Numeric.GSL.ODE | ||
18 | import Numeric.LinearAlgebra | ||
19 | import Numeric.LinearAlgebra.Util(mplot) | ||
20 | |||
21 | xdot t [x,v] = [v, -0.95*x - 0.1*v] | ||
22 | |||
23 | ts = linspace 100 (0,20 :: Double) | ||
24 | |||
25 | sol = odeSolve xdot [10,0] ts | ||
26 | |||
27 | main = mplot (ts : toColumns sol) | ||
28 | @ | ||
29 | |||
30 | -} | ||
31 | ----------------------------------------------------------------------------- | ||
32 | |||
33 | module Numeric.GSL.ODE ( | ||
34 | odeSolve, odeSolveV, ODEMethod(..), Jacobian | ||
35 | ) where | ||
36 | |||
37 | import Data.Packed.Internal | ||
38 | import Numeric.GSL.Internal | ||
39 | |||
40 | import Foreign.Ptr(FunPtr, nullFunPtr, freeHaskellFunPtr) | ||
41 | import Foreign.C.Types | ||
42 | import System.IO.Unsafe(unsafePerformIO) | ||
43 | |||
44 | ------------------------------------------------------------------------- | ||
45 | |||
46 | type Jacobian = Double -> Vector Double -> Matrix Double | ||
47 | |||
48 | -- | Stepping functions | ||
49 | data ODEMethod = RK2 -- ^ Embedded Runge-Kutta (2, 3) method. | ||
50 | | RK4 -- ^ 4th order (classical) Runge-Kutta. The error estimate is obtained by halving the step-size. For more efficient estimate of the error, use the embedded methods. | ||
51 | | RKf45 -- ^ Embedded Runge-Kutta-Fehlberg (4, 5) method. This method is a good general-purpose integrator. | ||
52 | | RKck -- ^ Embedded Runge-Kutta Cash-Karp (4, 5) method. | ||
53 | | RK8pd -- ^ Embedded Runge-Kutta Prince-Dormand (8,9) method. | ||
54 | | RK2imp Jacobian -- ^ Implicit 2nd order Runge-Kutta at Gaussian points. | ||
55 | | RK4imp Jacobian -- ^ Implicit 4th order Runge-Kutta at Gaussian points. | ||
56 | | BSimp Jacobian -- ^ Implicit Bulirsch-Stoer method of Bader and Deuflhard. The method is generally suitable for stiff problems. | ||
57 | | RK1imp Jacobian -- ^ Implicit Gaussian first order Runge-Kutta. Also known as implicit Euler or backward Euler method. Error estimation is carried out by the step doubling method. | ||
58 | | MSAdams -- ^ A variable-coefficient linear multistep Adams method in Nordsieck form. This stepper uses explicit Adams-Bashforth (predictor) and implicit Adams-Moulton (corrector) methods in P(EC)^m functional iteration mode. Method order varies dynamically between 1 and 12. | ||
59 | | MSBDF Jacobian -- ^ A variable-coefficient linear multistep backward differentiation formula (BDF) method in Nordsieck form. This stepper uses the explicit BDF formula as predictor and implicit BDF formula as corrector. A modified Newton iteration method is used to solve the system of non-linear equations. Method order varies dynamically between 1 and 5. The method is generally suitable for stiff problems. | ||
60 | |||
61 | |||
62 | -- | A version of 'odeSolveV' with reasonable default parameters and system of equations defined using lists. | ||
63 | odeSolve | ||
64 | :: (Double -> [Double] -> [Double]) -- ^ xdot(t,x) | ||
65 | -> [Double] -- ^ initial conditions | ||
66 | -> Vector Double -- ^ desired solution times | ||
67 | -> Matrix Double -- ^ solution | ||
68 | odeSolve xdot xi ts = odeSolveV RKf45 hi epsAbs epsRel (l2v xdot) (fromList xi) ts | ||
69 | where hi = (ts@>1 - ts@>0)/100 | ||
70 | epsAbs = 1.49012e-08 | ||
71 | epsRel = 1.49012e-08 | ||
72 | l2v f = \t -> fromList . f t . toList | ||
73 | |||
74 | -- | Evolution of the system with adaptive step-size control. | ||
75 | odeSolveV | ||
76 | :: ODEMethod | ||
77 | -> Double -- ^ initial step size | ||
78 | -> Double -- ^ absolute tolerance for the state vector | ||
79 | -> Double -- ^ relative tolerance for the state vector | ||
80 | -> (Double -> Vector Double -> Vector Double) -- ^ xdot(t,x) | ||
81 | -> Vector Double -- ^ initial conditions | ||
82 | -> Vector Double -- ^ desired solution times | ||
83 | -> Matrix Double -- ^ solution | ||
84 | odeSolveV RK2 = odeSolveV' 0 Nothing | ||
85 | odeSolveV RK4 = odeSolveV' 1 Nothing | ||
86 | odeSolveV RKf45 = odeSolveV' 2 Nothing | ||
87 | odeSolveV RKck = odeSolveV' 3 Nothing | ||
88 | odeSolveV RK8pd = odeSolveV' 4 Nothing | ||
89 | odeSolveV (RK2imp jac) = odeSolveV' 5 (Just jac) | ||
90 | odeSolveV (RK4imp jac) = odeSolveV' 6 (Just jac) | ||
91 | odeSolveV (BSimp jac) = odeSolveV' 7 (Just jac) | ||
92 | odeSolveV (RK1imp jac) = odeSolveV' 8 (Just jac) | ||
93 | odeSolveV MSAdams = odeSolveV' 9 Nothing | ||
94 | odeSolveV (MSBDF jac) = odeSolveV' 10 (Just jac) | ||
95 | |||
96 | |||
97 | odeSolveV' | ||
98 | :: CInt | ||
99 | -> Maybe (Double -> Vector Double -> Matrix Double) -- ^ optional jacobian | ||
100 | -> Double -- ^ initial step size | ||
101 | -> Double -- ^ absolute tolerance for the state vector | ||
102 | -> Double -- ^ relative tolerance for the state vector | ||
103 | -> (Double -> Vector Double -> Vector Double) -- ^ xdot(t,x) | ||
104 | -> Vector Double -- ^ initial conditions | ||
105 | -> Vector Double -- ^ desired solution times | ||
106 | -> Matrix Double -- ^ solution | ||
107 | odeSolveV' method mbjac h epsAbs epsRel f xiv ts = unsafePerformIO $ do | ||
108 | let n = dim xiv | ||
109 | fp <- mkDoubleVecVecfun (\t -> aux_vTov (checkdim1 n . f t)) | ||
110 | jp <- case mbjac of | ||
111 | Just jac -> mkDoubleVecMatfun (\t -> aux_vTom (checkdim2 n . jac t)) | ||
112 | Nothing -> return nullFunPtr | ||
113 | sol <- vec xiv $ \xiv' -> | ||
114 | vec (checkTimes ts) $ \ts' -> | ||
115 | createMIO (dim ts) n | ||
116 | (ode_c (method) h epsAbs epsRel fp jp // xiv' // ts' ) | ||
117 | "ode" | ||
118 | freeHaskellFunPtr fp | ||
119 | return sol | ||
120 | |||
121 | foreign import ccall safe "ode" | ||
122 | ode_c :: CInt -> Double -> Double -> Double -> FunPtr (Double -> TVV) -> FunPtr (Double -> TVM) -> TVVM | ||
123 | |||
124 | ------------------------------------------------------- | ||
125 | |||
126 | checkdim1 n v | ||
127 | | dim v == n = v | ||
128 | | otherwise = error $ "Error: "++ show n | ||
129 | ++ " components expected in the result of the function supplied to odeSolve" | ||
130 | |||
131 | checkdim2 n m | ||
132 | | rows m == n && cols m == n = m | ||
133 | | otherwise = error $ "Error: "++ show n ++ "x" ++ show n | ||
134 | ++ " Jacobian expected in odeSolve" | ||
135 | |||
136 | checkTimes ts | dim ts > 1 && all (>0) (zipWith subtract ts' (tail ts')) = ts | ||
137 | | otherwise = error "odeSolve requires increasing times" | ||
138 | where ts' = toList ts | ||