summaryrefslogtreecommitdiff
path: root/lib/Numeric/GSL
diff options
context:
space:
mode:
authorAlberto Ruiz <aruiz@um.es>2010-02-07 09:29:50 +0000
committerAlberto Ruiz <aruiz@um.es>2010-02-07 09:29:50 +0000
commitaef0333b5180ea79e539bd53194f1dfed20b7db5 (patch)
tree6ece2434ecacab194331120bd47d09ab04ae0f4f /lib/Numeric/GSL
parent634683fcfab73a0bd830fef03fb9f4603ba837b6 (diff)
added odeSolve
Diffstat (limited to 'lib/Numeric/GSL')
-rw-r--r--lib/Numeric/GSL/Internal.hs6
-rw-r--r--lib/Numeric/GSL/ODE.hs107
-rw-r--r--lib/Numeric/GSL/gsl-aux.c89
3 files changed, 201 insertions, 1 deletions
diff --git a/lib/Numeric/GSL/Internal.hs b/lib/Numeric/GSL/Internal.hs
index 834dfc2..37bcc1b 100644
--- a/lib/Numeric/GSL/Internal.hs
+++ b/lib/Numeric/GSL/Internal.hs
@@ -30,6 +30,9 @@ foreign import ccall "wrapper"
30foreign import ccall "wrapper" 30foreign import ccall "wrapper"
31 mkVecVecfun :: TVV -> IO (FunPtr TVV) 31 mkVecVecfun :: TVV -> IO (FunPtr TVV)
32 32
33foreign import ccall "wrapper"
34 mkDoubleVecVecfun :: (Double -> TVV) -> IO (FunPtr (Double -> TVV))
35
33aux_vTov :: (Vector Double -> Vector Double) -> TVV 36aux_vTov :: (Vector Double -> Vector Double) -> TVV
34aux_vTov f n p nr r = g where 37aux_vTov f n p nr r = g where
35 V {fptr = pr} = f x 38 V {fptr = pr} = f x
@@ -43,6 +46,9 @@ aux_vTov f n p nr r = g where
43foreign import ccall "wrapper" 46foreign import ccall "wrapper"
44 mkVecMatfun :: TVM -> IO (FunPtr TVM) 47 mkVecMatfun :: TVM -> IO (FunPtr TVM)
45 48
49foreign import ccall "wrapper"
50 mkDoubleVecMatfun :: (Double -> TVM) -> IO (FunPtr (Double -> TVM))
51
46aux_vTom :: (Vector Double -> Matrix Double) -> TVM 52aux_vTom :: (Vector Double -> Matrix Double) -> TVM
47aux_vTom f n p rr cr r = g where 53aux_vTom f n p rr cr r = g where
48 V {fptr = pr} = flatten $ f x 54 V {fptr = pr} = flatten $ f x
diff --git a/lib/Numeric/GSL/ODE.hs b/lib/Numeric/GSL/ODE.hs
new file mode 100644
index 0000000..3450b91
--- /dev/null
+++ b/lib/Numeric/GSL/ODE.hs
@@ -0,0 +1,107 @@
1{- |
2Module : Numeric.GSL.ODE
3Copyright : (c) Alberto Ruiz 2010
4License : GPL
5
6Maintainer : Alberto Ruiz (aruiz at um dot es)
7Stability : provisional
8Portability : uses ffi
9
10Solution of ordinary differential equation (ODE) initial value problems.
11
12<http://www.gnu.org/software/gsl/manual/html_node/Ordinary-Differential-Equations.html>
13
14A simple example:
15
16@import Numeric.GSL
17import Numeric.LinearAlgebra
18import Graphics.Plot
19
20xdot t [x,v] = [v, -0.95*x - 0.1*v]
21
22ts = linspace 100 (0,20)
23
24sol = odeSolve xdot [10,0] ts
25
26main = mplot (ts : toColumns sol)@
27
28-}
29-----------------------------------------------------------------------------
30
31module Numeric.GSL.ODE (
32 odeSolve, odeSolveV, ODEMethod(..)
33) where
34
35import Data.Packed.Internal
36import Data.Packed.Matrix
37import Foreign
38import Foreign.C.Types(CInt)
39import Numeric.GSL.Internal
40
41-------------------------------------------------------------------------
42
43-- | Stepping functions
44data ODEMethod = RK2 -- ^ Embedded Runge-Kutta (2, 3) method.
45 | RK4 -- ^ 4th order (classical) Runge-Kutta. The error estimate is obtained by halving the step-size. For more efficient estimate of the error, use 'RKf45'.
46 | RKf45 -- ^ Embedded Runge-Kutta-Fehlberg (4, 5) method. This method is a good general-purpose integrator.
47 | RKck -- ^ Embedded Runge-Kutta Cash-Karp (4, 5) method.
48 | RK8pd -- ^ Embedded Runge-Kutta Prince-Dormand (8,9) method.
49 | RK2imp -- ^ Implicit 2nd order Runge-Kutta at Gaussian points.
50 | RK4imp -- ^ Implicit 4th order Runge-Kutta at Gaussian points.
51 | BSimp -- ^ Implicit Bulirsch-Stoer method of Bader and Deuflhard. This algorithm requires the Jacobian.
52 | Gear1 -- ^ M=1 implicit Gear method.
53 | Gear2 -- ^ M=2 implicit Gear method.
54 deriving (Enum,Eq,Show,Bounded)
55
56-- | A version of 'odeSolveV' with reasonable default parameters and system of equations defined using lists.
57odeSolve
58 :: (Double -> [Double] -> [Double]) -- ^ xdot(t,x)
59 -> [Double] -- ^ initial conditions
60 -> Vector Double -- ^ desired solution times
61 -> Matrix Double -- ^ solution
62odeSolve xdot xi ts = odeSolveV RKf45 hi epsAbs epsRel (l2v xdot) Nothing (fromList xi) ts
63 where hi = (ts@>1 - ts@>0)/100
64 epsAbs = 1.49012e-08
65 epsRel = 1.49012e-08
66 l2v f = \t -> fromList . f t . toList
67 l2m f = \t -> fromLists . f t . toList
68
69-- | Evolution of the system with adaptive step-size control.
70odeSolveV
71 :: ODEMethod
72 -> Double -- ^ initial step size
73 -> Double -- ^ absolute tolerance for the state vector
74 -> Double -- ^ relative tolerance for the state vector
75 -> (Double -> Vector Double -> Vector Double) -- ^ xdot(t,x)
76 -> Maybe (Double -> Vector Double -> Matrix Double) -- ^ optional jacobian
77 -> Vector Double -- ^ initial conditions
78 -> Vector Double -- ^ desired solution times
79 -> Matrix Double -- ^ solution
80odeSolveV method h epsAbs epsRel f mbjac xiv ts = unsafePerformIO $ do
81 let n = dim xiv
82 fp <- mkDoubleVecVecfun (\t -> aux_vTov (checkdim1 n . f t))
83 jp <- case mbjac of
84 Just jac -> mkDoubleVecMatfun (\t -> aux_vTom (checkdim2 n . jac t))
85 Nothing -> return nullFunPtr
86 sol <- withVector xiv $ \xiv' ->
87 withVector ts $ \ts' ->
88 createMIO (dim ts) n
89 (ode_c (fi (fromEnum method)) h epsAbs epsRel fp jp // xiv' // ts' )
90 "ode"
91 freeHaskellFunPtr fp
92 return sol
93
94foreign import ccall "ode"
95 ode_c :: CInt -> Double -> Double -> Double -> FunPtr (Double -> TVV) -> FunPtr (Double -> TVM) -> TVVM
96
97-------------------------------------------------------
98
99checkdim1 n v
100 | dim v == n = v
101 | otherwise = error $ "Error: "++ show n
102 ++ " components expected in the result of the function supplied to odeSolve"
103
104checkdim2 n m
105 | rows m == n && cols m == n = m
106 | otherwise = error $ "Error: "++ show n ++ "x" ++ show n
107 ++ " Jacobian expected in odeSolve"
diff --git a/lib/Numeric/GSL/gsl-aux.c b/lib/Numeric/GSL/gsl-aux.c
index 0c71ca1..0fcde1c 100644
--- a/lib/Numeric/GSL/gsl-aux.c
+++ b/lib/Numeric/GSL/gsl-aux.c
@@ -22,6 +22,7 @@
22#include <gsl/gsl_complex_math.h> 22#include <gsl/gsl_complex_math.h>
23#include <gsl/gsl_rng.h> 23#include <gsl/gsl_rng.h>
24#include <gsl/gsl_randist.h> 24#include <gsl/gsl_randist.h>
25#include <gsl/gsl_odeiv.h>
25#include <string.h> 26#include <string.h>
26#include <stdio.h> 27#include <stdio.h>
27 28
@@ -507,7 +508,7 @@ double f_aux_min(const gsl_vector*x, void *pars) {
507 508
508 509
509void df_aux_min(const gsl_vector * x, void * pars, gsl_vector * g) { 510void df_aux_min(const gsl_vector * x, void * pars, gsl_vector * g) {
510 Tfdf * fdf = ((Tfdf*) pars); 511 Tfdf * fdf = ((Tfdf*) pars);
511 double* p = (double*)calloc(x->size,sizeof(double)); 512 double* p = (double*)calloc(x->size,sizeof(double));
512 double* q = (double*)calloc(g->size,sizeof(double)); 513 double* q = (double*)calloc(g->size,sizeof(double));
513 int k; 514 int k;
@@ -797,3 +798,89 @@ int random_vector(int seed, int code, RVEC(r)) {
797 } 798 }
798} 799}
799#undef RAN 800#undef RAN
801
802//////////////////////////////////////////////////////
803// ODE
804
805typedef struct {int n; int (*f)(double,int, const double*, int, double *); int (*j)(double,int, const double*, int, int, double*);} Tode;
806
807int odefunc (double t, const double y[], double f[], void *params) {
808 Tode * P = (Tode*) params;
809 (P->f)(t,P->n,y,P->n,f);
810 return GSL_SUCCESS;
811}
812
813int odejac (double t, const double y[], double *dfdy, double dfdt[], void *params) {
814 Tode * P = ((Tode*) params);
815 (P->j)(t,P->n,y,P->n,P->n,dfdy);
816 int j;
817 for (j=0; j< P->n; j++)
818 dfdt[j] = 0.0;
819 return GSL_SUCCESS;
820}
821
822
823int ode(int method, double h, double eps_abs, double eps_rel,
824 int f(double, int, const double*, int, double*),
825 int jac(double, int, const double*, int, int, double*),
826 KRVEC(xi), KRVEC(ts), RMAT(sol)) {
827
828 const gsl_odeiv_step_type * T;
829
830 switch(method) {
831 case 0 : {T = gsl_odeiv_step_rk2; break; }
832 case 1 : {T = gsl_odeiv_step_rk4; break; }
833 case 2 : {T = gsl_odeiv_step_rkf45; break; }
834 case 3 : {T = gsl_odeiv_step_rkck; break; }
835 case 4 : {T = gsl_odeiv_step_rk8pd; break; }
836 case 5 : {T = gsl_odeiv_step_rk2imp; break; }
837 case 6 : {T = gsl_odeiv_step_rk4imp; break; }
838 case 7 : {T = gsl_odeiv_step_bsimp; break; }
839 case 8 : {T = gsl_odeiv_step_gear1; break; }
840 case 9 : {T = gsl_odeiv_step_gear2; break; }
841 default: ERROR(BAD_CODE);
842 }
843
844
845 gsl_odeiv_step * s = gsl_odeiv_step_alloc (T, xin);
846 gsl_odeiv_control * c = gsl_odeiv_control_y_new (eps_abs, eps_rel);
847 gsl_odeiv_evolve * e = gsl_odeiv_evolve_alloc (xin);
848
849 Tode P;
850 P.f = f;
851 P.j = jac;
852 P.n = xin;
853
854 gsl_odeiv_system sys = {odefunc, odejac, xin, &P};
855
856 double t = tsp[0];
857
858 double* y = (double*)calloc(xin,sizeof(double));
859 int i,j;
860 for(i=0; i< xin; i++) {
861 y[i] = xip[i];
862 solp[i] = xip[i];
863 }
864
865 for (i = 1; i < tsn ; i++)
866 {
867 double ti = tsp[i];
868 while (t < ti)
869 {
870 gsl_odeiv_evolve_apply (e, c, s,
871 &sys,
872 &t, ti, &h,
873 y);
874 // if (h < hmin) h = hmin;
875 }
876 for(j=0; j<xin; j++) {
877 solp[i*xin + j] = y[j];
878 }
879 }
880
881 free(y);
882 gsl_odeiv_evolve_free (e);
883 gsl_odeiv_control_free (c);
884 gsl_odeiv_step_free (s);
885 return 0;
886}