Skip to content

Commit

Permalink
Runge-Kutta implicit methods added
Browse files Browse the repository at this point in the history
  • Loading branch information
qnikst committed Apr 21, 2012
1 parent b22c761 commit b8f2e3f
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 53 deletions.
85 changes: 85 additions & 0 deletions src/Examples/KeplerSimple1.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{-# LANGUAGE BangPatterns,TypeFamilies #-}
import Data.AdditiveGroup
import Data.VectorSpace
import qualified Data.Vector as V
import Control.Monad.ST

import Debug.Trace
import Math.Integrators.StormerVerlet
import Math.Integrators.ExplicitEuler
import Math.Integrators.ImplicitEuler
import Math.Integrators.Internal
import Math.Integrators


import Data.Accessor
import Graphics.Rendering.Chart
import Data.Colour.Names
import Data.Colour



data T3 = T3 !Double !Double deriving (Eq,Show)
data T2 = T2 !T3 !T3 deriving (Eq,Show)

instance AdditiveGroup T3 where
zeroV = T3 zeroV zeroV
negateV (T3 x y) = T3 (negateV x) (negateV y)
(T3 x1 y1) ^+^ (T3 x2 y2) = T3 (x1^+^x2) (y1^+^y2)

instance VectorSpace T3 where
type Scalar T3 = Double
c *^ (T3 x y) = T3 (c*^x) (c*^y)

instance InnerSpace T3 where
(T3 x1 y1) <.> (T3 x2 y2) = x1*x2+y1*y2

instance AdditiveGroup T2 where
zeroV = T2 zeroV zeroV
negateV (T2 x y) = T2 (negateV x) (negateV y)
(T2 a1 a2) ^+^ (T2 b1 b2) = T2 (a1^+^b1) (a2^+^b2)

instance VectorSpace T2 where
type Scalar T2 = Double
c *^ (T2 a1 a2) = T2 (c*^a1) (c*^a2)


kepler :: T2 -> T2
kepler (T2 q1 q2) =
let r = q2 ^-^ q1 -- q2 - q1
ri = r <.> r -- ||q2-q1||^2
rr = ri * (sqrt ri)
q1' = r ^/ rr
q2' = negateV q1'
in T2 q1' q2'


k2p = \h (v,x) ->
let v' = (implicitEuler (\_ -> kepler x) norm) h v
x' = (implicitEuler (\_ -> v') norm) h x
in (v',x')


norm (T2 x y) = x<.>x + y<.>y

norm2 (a,b) = (norm a)*(norm a)+(norm b)*(norm b)


tm = V.enumFromStepN 0 0.001 100000
result1 = runST $ integrateV (stormerVerlet2 kepler) ((T2 (T3 1 0) (T3 0 1)),(T2 (T3 (-1) (-1)) (T3 1 1))) tm
result2 = runST $ integrateV (k2p) ((T2 (T3 1 0) (T3 0 1)),(T2 (T3 (-1) 0) (T3 1 0))) tm

plot1 r = renderableToPNGFile (mychart) 640 480 "all.png"
where
mychart = toRenderable layout
layout = layout1_title ^= "bugs"
$ layout1_plots ^= [Left (toPlot plot1),Left (toPlot plot2)]
$ defaultLayout1
plot1 = plot_lines_style .> line_color ^= opaque blue
$ plot_lines_title ^= "body-1"
$ plot_lines_values ^= [map (\(_,T2 (T3 x y) _) -> (x,y)) (V.toList r)]
$ defaultPlotLines
plot2 = plot_lines_style .> line_color ^= opaque red
$ plot_lines_title ^= "body-2"
$ plot_lines_values ^= [map (\(_,T2 _ (T3 x y)) -> (x,y)) (V.toList r)]
$ defaultPlotLines
217 changes: 217 additions & 0 deletions src/Examples/LottkaVolterra.lhs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
> {-# LANGUAGE FlexibleInstances, BangPatterns, TypeFamilies #-}
> module Examples.LottkaVollterra
> where

First we import some stuff that we will use for compulations.
All computations will run it ST monad and we will use Vector
to store results, it not the most effective way to do it in
haskell but it is quite common in numerical engines (like Octave,
Matlab, etc.)
For generazation of algorithms on arbitrary space we'll use
VectorSpace.

> import Prelude hiding (sequence)
> import Control.Monad.ST
> import Control.Monad
> import Data.Vector (Vector,(!))
> import qualified Data.Vector as V
> import Data.AdditiveGroup
> import Data.VectorSpace

Then we import some stuff for plotting graphs

> import Data.Accessor
> import Graphics.Rendering.Chart
> import Data.Colour.Names
> import Data.Colour

And now our main part


> import Math.Integrators
> import Math.Integrators.ExplicitEuler
> import Math.Integrators.ImplicitEuler
> import Math.Integrators.ImplicitMidpointRule
> import Math.Integrators.SympleticEuler


First model will be Lotka-Volterra model, that was used to
estimate predators-prey number

[1] http://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equation
\begin{equation}
\left\{
\begin{array}{ccc}
\dot{u} & = & u (v - 2) \\
\dot{v} & = & v (1 - u)
\end{array}
\right.
\end{equation}

To store our $R^2$ space we'll use special data type, that is
strict and has fixed size

> data T2 = T2 !Double !Double
> deriving (Eq,Show)

To be able to use it we need to make it instance of vector space:

> instance AdditiveGroup T2 where
> zeroV = T2 0 0
> negateV (T2 x y) = T2 (-x) (-y)
> (T2 a1 a2) ^+^ (T2 b1 b2) = T2 (a1+b1) (a2+b2)

> instance VectorSpace T2 where
> type Scalar T2 = Double
> c *^ (T2 a1 a2) = T2 (c*a1) (c*a2)


Now let's define our equation:

> lv :: T2 -> T2
> lv (T2 u v) = T2 (u * (v-2)) (v * (1-u))

Create initial condition list (maybe I'll use it)

> ics = [ T2 2 2, T2 4 8, T2 4 2,T2 6 2]

Create initial conditions for testing purposes

> ic = T2 2 2

That LV equation has next first integral that should be preserved:

> realline :: T2 -> Double
> realline (T2 u v) = (log u) - u + 2*(log v) -v

Define a function that find difference in first integrals (i.e. error)

> errorV ic v = V.map (\x -> abs $! (realline x) - (realline ic)) v

We'll use solve equation from 0 to 100 with 0.12 step

> tm = V.enumFromStepN 0 0.12 100

Our solvers:

> solve1 ic tm = runST $ integrateV (explicitEuler lv) ic tm
> solve2 ic tm = runST $ integrateV (implicitEuler lv norm) ic tm
> solve3 ic tm = runST $ integrateV (imr lv norm) ic tm

some results:

> result1 = solve1 ic tm
> result2 = solve2 ic tm
> result3 = solve3 ic tm

to use sympletic method we should redefine out equation
in this place I really need an advice how to do it implictly in terms
of First Order functions

> splitIc :: T2 -> (Double,Double)
> splitIc (T2 u v) = (u,v)

> splitLv :: ((Double -> Double -> Double),(Double->Double->Double))
> splitLv = (\u v -> u*(v-2), \u v -> v*(1-u))

> solve4 ic tm = runST $ integrateV (sympleticEuler1 splitLv abs) (splitIc ic) tm
> result4 = solve4 ic tm

Some helpers: norm on T2 space

> norm :: T2 -> Double
> norm (T2 a b) = a*a+b*b

Now lets create charts:
first: plot all graphs on the same plot:

> plot1 = renderableToPNGFile (mychart) 640 480 "all.png"
> where
> mychart = chart "All methods" lst
> lst = [("Explicit Euler", blue, f solve1)
> ,("Implicit Euler", green, f solve2)
> ,("Implicit Midpoint Rule", red, f solve3)
> ,("Sympletic Euler", magenta, f' solve4)]
> f g = v2d $! g ic tm
> f' g = V.toList $! g ic tm
> plotI fn nm f ics = renderableToPNGFile (mychart) 640 480 fn
> where
> mychart = chart nm lst
> lst = zipWith3 (\x y z -> (x,y,z)) (map show ics) [blue,green,red,magenta,orange] (map f ics)
> plotE fn nm f ics = renderableToPNGFile (mychart) 640 480 fn
> where
> mychart = chart nm lst
> lst = zipWith3 (\x y z -> (x,y,z)) (map show ics) [blue,green,red,magenta,orange]
> (map (\i -> zipWith (,) (V.toList tm) (V.toList $! errorV i $! f i)) ics)
> plot2 = plotI "1.png" "Explicit Euler" (v2d . (flip solve1 tm)) ics
> plot3 = plotI "2.png" "Implicit Euler" (v2d . (flip solve2 tm)) ics
> plot4 = plotI "3.png" "IMR" (v2d . (flip solve3 tm)) ics
> plot5 = plotI "4.png" "Sypletic" (V.toList . (flip solve4 tm)) ics
> plot6 = plotE "1e.png" "Explicit Euler Error" (flip solve1 tm) ics
> plot7 = plotE "2e.png" "Implicit Euler Error" (flip solve2 tm) ics
> plot8 = plotE "3e.png" "IMR Error" (flip solve3 tm) ics
> --plot7 = plotE "2e.png" "Implicit Euler Error" (flip solve2 tm) ics
> chart tit lst = toRenderable layout
> where
> plotList = map (Left . toPlot . mtp) lst
> mtp (tit,clr,dt) = plot_lines_style .> line_color ^= opaque clr
> $ plot_lines_title ^= tit
> $ plot_lines_values ^= [dt]
> $ defaultPlotLines
> layout = layout1_plots ^= plotList
> $ layout1_title ^= tit
> $ defaultLayout1
> v2d = (map (\(T2 x y) -> (x,y))) . V.toList

chart = toRenderable layout
where
plot1 = plot_lines_style .> line_color ^= opaque blue
$ plot_lines_title ^= "explicit euler"
$ plot_lines_values ^= [[ (x,y) | (T2 x y) <- V.toList result1]]
$ defaultPlotLines
plot2 = plot_lines_style .> line_color ^= opaque green
$ plot_lines_title ^= "implicit euler"
$ plot_lines_values ^= [[ (x,y) | (T2 x y) <- V.toList result2]]
$ defaultPlotLines
plot3 = plot_lines_style .> line_color ^= opaque red
$ plot_lines_title ^= "implict midpoint rule"
$ plot_lines_values ^= [[ (x,y) | (T2 x y) <- V.toList result3]]
$ defaultPlotLines
plot4 = plot_lines_style .> line_color ^= opaque magenta
$ plot_lines_title ^= "sympletic euler"
$ plot_lines_values ^= [[ (x,y) | (x, y) <- V.toList result4]]
$ defaultPlotLines
layout = layout1_plots ^= [Left (toPlot plot1),Left (toPlot plot2), Left (toPlot plot3), Left (toPlot plot4)]
$ layout1_title ^= "Lottka-Volterra system"
$ defaultLayout1

chart2 = toRenderable layout
where
t1 = V.toList (errorV ic result1)
t2 = V.toList (errorV ic result2)
t3 = V.toList (errorV ic result3)
plot1 = plot_lines_style .> line_color ^= opaque blue
$ plot_lines_title ^= "explicit euler"
$ plot_lines_values ^= [zipWith (,) [1..] t1]
$ defaultPlotLines
plot2 = plot_lines_style .> line_color ^= opaque green
$ plot_lines_title ^= "implicit euler"
$ plot_lines_values ^= [zipWith (,) [1..] t2]
$ defaultPlotLines
plot3 = plot_lines_style .> line_color ^= opaque red
$ plot_lines_title ^= "implict midpoint rule"
$ plot_lines_values ^= [zipWith (,) ([1..]::[Double]) t3]
$ defaultPlotLines
{- plot4 = plot_lines_style .> line_color ^= opaque magenta
$ plot_lines_title ^= "sympletic euler"
$ plot_lines_values ^= [[ (x,y) | (x, y) <- V.toList result4]]
$ defaultPlotLines-}
-- lot = plot_lines_values ^= [[ (x,y) | (T2 x y) <- V.toList result3]]
-- $ defaultPlotLines
layout = layout1_plots ^= [Left (toPlot plot1),Left (toPlot plot2), Left (toPlot plot3){-, Left (toPlot plot4)-}]
$ layout1_title ^= "Lottka-Volterra system error"
$ defaultLayout1
plott = renderableToPNGFile (chart) 640 480 "tmp.png"
plott2 = renderableToPNGFile (chart2) 640 580 "tmp2.png"
17 changes: 9 additions & 8 deletions src/Math/Integrators/RK.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ module Math.Integrators.RK
rk45
, rk46
-- * implicit methods
, gauss4
{- , gauss4
, gauss6
, lobattoIIIA4
, lobattoIIIA6
, lobattoIIIB4
, lobattoIIIB4-}
)
where

import Math.Integrators.RK.Template
import Math.Integrators.RK.Types
import Math.Integrators.Internal
import Math.Integrators.Implicit
import Data.VectorSpace


Expand All @@ -41,15 +43,15 @@ rk46 = [qrk|
|]


gauss4 :: (VectorSpace a, Floating (Scalar a)) => (Double -> a -> a) -> Integrator (Double,a)
gauss4 :: (VectorSpace a, Floating (Scalar a)) => (ImplicitRkType (a,a)) -> (Double -> a -> a) -> Integrator (Double,a)
gauss4 = [qrk|
0.5 - sqrt(3)/6 | 0.25 & 0.25 - sqrt(3)/6
0.5 + sqrt(3)/6 | 0.25 + sqrt(3)/6 & 1/4
- - - - - - - - + - - - - - - - - - - -
| 0.5 & 0.5
|]

gauss6 :: (VectorSpace a, Floating (Scalar a)) => (Double -> a -> a) -> Integrator (Double,a)
gauss6 :: (VectorSpace a, Floating (Scalar a)) => (ImplicitRkType (a,a,a)) -> (Double -> a -> a) -> Integrator (Double,a)
gauss6 = [qrk|
0.5 - sqrt(15)/10 | 5/36 & 2/9 - sqrt(15)/15 & 5/36 - sqrt(15)/30
0.5 | 5/36 + sqrt(15)/24 & 2/9 & 5/36 - sqrt(15)/24
Expand All @@ -58,7 +60,7 @@ gauss6 = [qrk|
| 5/18 & 4/9 & 5/18
|]

lobattoIIIA4 :: (VectorSpace a, Floating (Scalar a)) => (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIA4 :: (VectorSpace a, Floating (Scalar a)) => (ImplicitRkType (a,a,a)) -> (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIA4 = [qrk|
0 | 0 & 0 & 0
0.5 | 5/24 & 1/3 & -1/24
Expand All @@ -67,7 +69,7 @@ lobattoIIIA4 = [qrk|
| 1/6 & 2/3 & 1/6
|]

lobattoIIIA6 :: (VectorSpace a, Floating (Scalar a)) => (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIA6 :: (VectorSpace a, Floating (Scalar a)) => (ImplicitRkType (a,a,a,a)) -> (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIA6 = [qrk|
0 | 0 & 0 & 0 & 0
(5-sqrt(5))/10 | (11+sqrt(5))/120 & (25-sqrt(5))/120 & (25 - 13 *sqrt(5)/120) & (-1+sqrt(5))/120
Expand All @@ -77,12 +79,11 @@ lobattoIIIA6 = [qrk|
| 1/12 & 5/12 & 5/12 & 1/12
|]

lobattoIIIB4 :: (VectorSpace a, Floating (Scalar a)) => (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIB4 :: (VectorSpace a, Floating (Scalar a)) => (ImplicitRkType (a,a,a)) -> (Double -> a -> a) -> Integrator (Double,a)
lobattoIIIB4 = [qrk|
0 | 1/6 & -1/6 & 0
0.5 | 1/6 & 1/3 & 0
1 | 1/6 & 5/6 & 0
- - + - - - - - - - - -
| 1/6 & 2/3 & 1/6
|]

1 change: 1 addition & 0 deletions src/Math/Integrators/RK/Internal.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Math.Integrators.RK.Internal
( MExp(..)
, isExplicit
)
where

Expand Down
Loading

0 comments on commit b8f2e3f

Please sign in to comment.