diff options
Diffstat (limited to 'packages/sundials')
-rw-r--r-- | packages/sundials/ChangeLog.md | 5 | ||||
-rw-r--r-- | packages/sundials/LICENSE | 30 | ||||
-rw-r--r-- | packages/sundials/README.md | 8 | ||||
-rw-r--r-- | packages/sundials/Setup.hs | 2 | ||||
-rw-r--r-- | packages/sundials/diagrams/brusselator.png | bin | 27362 -> 0 bytes | |||
-rw-r--r-- | packages/sundials/hmatrix-sundials.cabal | 61 | ||||
-rw-r--r-- | packages/sundials/src/Main.hs | 186 | ||||
-rw-r--r-- | packages/sundials/src/Numeric/Sundials/ARKode/ODE.hs | 896 | ||||
-rw-r--r-- | packages/sundials/src/Numeric/Sundials/Arkode.hsc | 204 | ||||
-rw-r--r-- | packages/sundials/src/Numeric/Sundials/CVode/ODE.hs | 471 | ||||
-rw-r--r-- | packages/sundials/src/Numeric/Sundials/ODEOpts.hs | 32 | ||||
-rw-r--r-- | packages/sundials/src/helpers.c | 44 | ||||
-rw-r--r-- | packages/sundials/src/helpers.h | 9 |
13 files changed, 0 insertions, 1948 deletions
diff --git a/packages/sundials/ChangeLog.md b/packages/sundials/ChangeLog.md deleted file mode 100644 index 7b15777..0000000 --- a/packages/sundials/ChangeLog.md +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | # Revision history for hmatrix-sundials | ||
2 | |||
3 | ## 0.1.0.0 -- 2018-04-21 | ||
4 | |||
5 | * First version. Released on an unsuspecting world. Just Runge-Kutta methods to start with. | ||
diff --git a/packages/sundials/LICENSE b/packages/sundials/LICENSE deleted file mode 100644 index a162e98..0000000 --- a/packages/sundials/LICENSE +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | Copyright (c) 2018, Dominic Steinitz, Novadiscovery | ||
2 | |||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | * Redistributions in binary form must reproduce the above | ||
12 | copyright notice, this list of conditions and the following | ||
13 | disclaimer in the documentation and/or other materials provided | ||
14 | with the distribution. | ||
15 | |||
16 | * Neither the name of Dominic Steinitz nor the names of other | ||
17 | contributors may be used to endorse or promote products derived | ||
18 | from this software without specific prior written permission. | ||
19 | |||
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/packages/sundials/README.md b/packages/sundials/README.md deleted file mode 100644 index 2fac5c2..0000000 --- a/packages/sundials/README.md +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | Currently only an interface to the Runge-Kutta methods: | ||
2 | [ARKode](https://computation.llnl.gov/projects/sundials/arkode) | ||
3 | |||
4 | The interface is almost certainly going to change. Sundials gives a | ||
5 | rich set of "combinators" for controlling the solution of your problem | ||
6 | and reporting on how it performed. The idea is to initially mimic | ||
7 | hmatrix-gsl and add extra, richer functions but ultimately upgrade the | ||
8 | whole interface both for sundials and for gsl. | ||
diff --git a/packages/sundials/Setup.hs b/packages/sundials/Setup.hs deleted file mode 100644 index 9a994af..0000000 --- a/packages/sundials/Setup.hs +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | import Distribution.Simple | ||
2 | main = defaultMain | ||
diff --git a/packages/sundials/diagrams/brusselator.png b/packages/sundials/diagrams/brusselator.png deleted file mode 100644 index 740cacb..0000000 --- a/packages/sundials/diagrams/brusselator.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/packages/sundials/hmatrix-sundials.cabal b/packages/sundials/hmatrix-sundials.cabal deleted file mode 100644 index cd2be4e..0000000 --- a/packages/sundials/hmatrix-sundials.cabal +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | name: hmatrix-sundials | ||
2 | version: 0.19.0.0 | ||
3 | synopsis: hmatrix interface to sundials | ||
4 | description: An interface to the solving suite SUNDIALS. Currently, it | ||
5 | mimics the solving interface in hmstrix-gsl but | ||
6 | provides more diagnostic information and the | ||
7 | Butcher Tableaux (for Runge-Kutta methods). | ||
8 | homepage: https://github.com/idontgetoutmuch/hmatrix/tree/sundials | ||
9 | license: BSD3 | ||
10 | license-file: LICENSE | ||
11 | author: Dominic Steinitz | ||
12 | maintainer: dominic@steinitz.org | ||
13 | copyright: Dominic Steinitz 2018, Novadiscovery 2018 | ||
14 | category: Math | ||
15 | build-type: Simple | ||
16 | extra-source-files: ChangeLog.md, README.md, diagrams/*.png | ||
17 | extra-doc-files: diagrams/*.png | ||
18 | cabal-version: >=1.18 | ||
19 | |||
20 | |||
21 | library | ||
22 | build-depends: base >=4.10 && <4.11, | ||
23 | inline-c >=0.6 && <0.7, | ||
24 | vector >=0.12 && <0.13, | ||
25 | template-haskell >=2.12 && <2.13, | ||
26 | containers >=0.5 && <0.6, | ||
27 | hmatrix>=0.18 | ||
28 | extra-libraries: sundials_arkode, | ||
29 | sundials_cvode | ||
30 | other-extensions: QuasiQuotes | ||
31 | hs-source-dirs: src | ||
32 | exposed-modules: Numeric.Sundials.ODEOpts, | ||
33 | Numeric.Sundials.ARKode.ODE, | ||
34 | Numeric.Sundials.CVode.ODE | ||
35 | other-modules: Numeric.Sundials.Arkode | ||
36 | c-sources: src/helpers.c src/helpers.h | ||
37 | default-language: Haskell2010 | ||
38 | |||
39 | test-suite hmatrix-sundials-testsuite | ||
40 | type: exitcode-stdio-1.0 | ||
41 | main-is: Main.hs | ||
42 | other-modules: Numeric.Sundials.ODEOpts, | ||
43 | Numeric.Sundials.ARKode.ODE, | ||
44 | Numeric.Sundials.CVode.ODE, | ||
45 | Numeric.Sundials.Arkode | ||
46 | build-depends: base >=4.10 && <4.11, | ||
47 | inline-c >=0.6 && <0.7, | ||
48 | vector >=0.12 && <0.13, | ||
49 | template-haskell >=2.12 && <2.13, | ||
50 | containers >=0.5 && <0.6, | ||
51 | hmatrix>=0.18, | ||
52 | plots, | ||
53 | diagrams-lib, | ||
54 | diagrams-rasterific, | ||
55 | lens, | ||
56 | hspec | ||
57 | hs-source-dirs: src | ||
58 | extra-libraries: sundials_arkode, | ||
59 | sundials_cvode | ||
60 | c-sources: src/helpers.c src/helpers.h | ||
61 | default-language: Haskell2010 | ||
diff --git a/packages/sundials/src/Main.hs b/packages/sundials/src/Main.hs deleted file mode 100644 index 16c21c5..0000000 --- a/packages/sundials/src/Main.hs +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | {-# OPTIONS_GHC -Wall #-} | ||
2 | |||
3 | import qualified Numeric.Sundials.ARKode.ODE as ARK | ||
4 | import qualified Numeric.Sundials.CVode.ODE as CV | ||
5 | import Numeric.LinearAlgebra | ||
6 | |||
7 | import Plots as P | ||
8 | import qualified Diagrams.Prelude as D | ||
9 | import Diagrams.Backend.Rasterific | ||
10 | |||
11 | import Control.Lens | ||
12 | |||
13 | import Test.Hspec | ||
14 | |||
15 | |||
16 | lorenz :: Double -> [Double] -> [Double] | ||
17 | lorenz _t u = [ sigma * (y - x) | ||
18 | , x * (rho - z) - y | ||
19 | , x * y - beta * z | ||
20 | ] | ||
21 | where | ||
22 | rho = 28.0 | ||
23 | sigma = 10.0 | ||
24 | beta = 8.0 / 3.0 | ||
25 | x = u !! 0 | ||
26 | y = u !! 1 | ||
27 | z = u !! 2 | ||
28 | |||
29 | _lorenzJac :: Double -> Vector Double -> Matrix Double | ||
30 | _lorenzJac _t u = (3><3) [ (-sigma), rho - z, y | ||
31 | , sigma , -1.0 , x | ||
32 | , 0.0 , (-x) , (-beta) | ||
33 | ] | ||
34 | where | ||
35 | rho = 28.0 | ||
36 | sigma = 10.0 | ||
37 | beta = 8.0 / 3.0 | ||
38 | x = u ! 0 | ||
39 | y = u ! 1 | ||
40 | z = u ! 2 | ||
41 | |||
42 | brusselator :: Double -> [Double] -> [Double] | ||
43 | brusselator _t x = [ a - (w + 1) * u + v * u * u | ||
44 | , w * u - v * u * u | ||
45 | , (b - w) / eps - w * u | ||
46 | ] | ||
47 | where | ||
48 | a = 1.0 | ||
49 | b = 3.5 | ||
50 | eps = 5.0e-6 | ||
51 | u = x !! 0 | ||
52 | v = x !! 1 | ||
53 | w = x !! 2 | ||
54 | |||
55 | _brussJac :: Double -> Vector Double -> Matrix Double | ||
56 | _brussJac _t x = (3><3) [ (-(w + 1.0)) + 2.0 * u * v, w - 2.0 * u * v, (-w) | ||
57 | , u * u , (-(u * u)) , 0.0 | ||
58 | , (-u) , u , (-1.0) / eps - u | ||
59 | ] | ||
60 | where | ||
61 | y = toList x | ||
62 | u = y !! 0 | ||
63 | v = y !! 1 | ||
64 | w = y !! 2 | ||
65 | eps = 5.0e-6 | ||
66 | |||
67 | stiffish :: Double -> [Double] -> [Double] | ||
68 | stiffish t v = [ lamda * u + 1.0 / (1.0 + t * t) - lamda * atan t ] | ||
69 | where | ||
70 | lamda = -100.0 | ||
71 | u = v !! 0 | ||
72 | |||
73 | stiffishV :: Double -> Vector Double -> Vector Double | ||
74 | stiffishV t v = fromList [ lamda * u + 1.0 / (1.0 + t * t) - lamda * atan t ] | ||
75 | where | ||
76 | lamda = -100.0 | ||
77 | u = v ! 0 | ||
78 | |||
79 | _stiffJac :: Double -> Vector Double -> Matrix Double | ||
80 | _stiffJac _t _v = (1><1) [ lamda ] | ||
81 | where | ||
82 | lamda = -100.0 | ||
83 | |||
84 | predatorPrey :: Double -> [Double] -> [Double] | ||
85 | predatorPrey _t v = [ x * a - b * x * y | ||
86 | , d * x * y - c * y - e * y * z | ||
87 | , (-f) * z + g * y * z | ||
88 | ] | ||
89 | where | ||
90 | x = v!!0 | ||
91 | y = v!!1 | ||
92 | z = v!!2 | ||
93 | a = 1.0 | ||
94 | b = 1.0 | ||
95 | c = 1.0 | ||
96 | d = 1.0 | ||
97 | e = 1.0 | ||
98 | f = 1.0 | ||
99 | g = 1.0 | ||
100 | |||
101 | lSaxis :: [[Double]] -> P.Axis B D.V2 Double | ||
102 | lSaxis xs = P.r2Axis &~ do | ||
103 | let ts = xs!!0 | ||
104 | us = xs!!1 | ||
105 | vs = xs!!2 | ||
106 | ws = xs!!3 | ||
107 | P.linePlot' $ zip ts us | ||
108 | P.linePlot' $ zip ts vs | ||
109 | P.linePlot' $ zip ts ws | ||
110 | |||
111 | kSaxis :: [(Double, Double)] -> P.Axis B D.V2 Double | ||
112 | kSaxis xs = P.r2Axis &~ do | ||
113 | P.linePlot' xs | ||
114 | |||
115 | main :: IO () | ||
116 | main = do | ||
117 | |||
118 | let res1 = ARK.odeSolve brusselator [1.2, 3.1, 3.0] (fromList [0.0, 0.1 .. 10.0]) | ||
119 | renderRasterific "diagrams/brusselator.png" | ||
120 | (D.dims2D 500.0 500.0) | ||
121 | (renderAxis $ lSaxis $ [0.0, 0.1 .. 10.0]:(toLists $ tr res1)) | ||
122 | |||
123 | let res1a = ARK.odeSolve brusselator [1.2, 3.1, 3.0] (fromList [0.0, 0.1 .. 10.0]) | ||
124 | renderRasterific "diagrams/brusselatorA.png" | ||
125 | (D.dims2D 500.0 500.0) | ||
126 | (renderAxis $ lSaxis $ [0.0, 0.1 .. 10.0]:(toLists $ tr res1a)) | ||
127 | |||
128 | let res2 = ARK.odeSolve stiffish [0.0] (fromList [0.0, 0.1 .. 10.0]) | ||
129 | renderRasterific "diagrams/stiffish.png" | ||
130 | (D.dims2D 500.0 500.0) | ||
131 | (renderAxis $ kSaxis $ zip [0.0, 0.1 .. 10.0] (concat $ toLists res2)) | ||
132 | |||
133 | let res2a = ARK.odeSolveV (ARK.SDIRK_5_3_4') Nothing 1e-6 1e-10 stiffishV (fromList [0.0]) (fromList [0.0, 0.1 .. 10.0]) | ||
134 | |||
135 | let res2b = ARK.odeSolveV (ARK.TRBDF2_3_3_2') Nothing 1e-6 1e-10 stiffishV (fromList [0.0]) (fromList [0.0, 0.1 .. 10.0]) | ||
136 | |||
137 | let maxDiffA = maximum $ map abs $ | ||
138 | zipWith (-) ((toLists $ tr res2a)!!0) ((toLists $ tr res2b)!!0) | ||
139 | |||
140 | let res2c = CV.odeSolveV (CV.BDF) Nothing 1e-6 1e-10 stiffishV (fromList [0.0]) (fromList [0.0, 0.1 .. 10.0]) | ||
141 | |||
142 | let maxDiffB = maximum $ map abs $ | ||
143 | zipWith (-) ((toLists $ tr res2a)!!0) ((toLists $ tr res2c)!!0) | ||
144 | |||
145 | let maxDiffC = maximum $ map abs $ | ||
146 | zipWith (-) ((toLists $ tr res2b)!!0) ((toLists $ tr res2c)!!0) | ||
147 | |||
148 | let res3 = ARK.odeSolve lorenz [-5.0, -5.0, 1.0] (fromList [0.0, 0.01 .. 10.0]) | ||
149 | |||
150 | renderRasterific "diagrams/lorenz.png" | ||
151 | (D.dims2D 500.0 500.0) | ||
152 | (renderAxis $ kSaxis $ zip ((toLists $ tr res3)!!0) ((toLists $ tr res3)!!1)) | ||
153 | |||
154 | renderRasterific "diagrams/lorenz1.png" | ||
155 | (D.dims2D 500.0 500.0) | ||
156 | (renderAxis $ kSaxis $ zip ((toLists $ tr res3)!!0) ((toLists $ tr res3)!!2)) | ||
157 | |||
158 | renderRasterific "diagrams/lorenz2.png" | ||
159 | (D.dims2D 500.0 500.0) | ||
160 | (renderAxis $ kSaxis $ zip ((toLists $ tr res3)!!1) ((toLists $ tr res3)!!2)) | ||
161 | |||
162 | let res4 = CV.odeSolve predatorPrey [0.5, 1.0, 2.0] (fromList [0.0, 0.01 .. 10.0]) | ||
163 | |||
164 | renderRasterific "diagrams/predatorPrey.png" | ||
165 | (D.dims2D 500.0 500.0) | ||
166 | (renderAxis $ kSaxis $ zip ((toLists $ tr res4)!!0) ((toLists $ tr res4)!!1)) | ||
167 | |||
168 | renderRasterific "diagrams/predatorPrey1.png" | ||
169 | (D.dims2D 500.0 500.0) | ||
170 | (renderAxis $ kSaxis $ zip ((toLists $ tr res4)!!0) ((toLists $ tr res4)!!2)) | ||
171 | |||
172 | renderRasterific "diagrams/predatorPrey2.png" | ||
173 | (D.dims2D 500.0 500.0) | ||
174 | (renderAxis $ kSaxis $ zip ((toLists $ tr res4)!!1) ((toLists $ tr res4)!!2)) | ||
175 | |||
176 | let res4a = ARK.odeSolve predatorPrey [0.5, 1.0, 2.0] (fromList [0.0, 0.01 .. 10.0]) | ||
177 | |||
178 | let maxDiffPpA = maximum $ map abs $ | ||
179 | zipWith (-) ((toLists $ tr res4)!!0) ((toLists $ tr res4a)!!0) | ||
180 | |||
181 | hspec $ describe "Compare results" $ do | ||
182 | it "for SDIRK_5_3_4' and TRBDF2_3_3_2'" $ maxDiffA < 1.0e-6 | ||
183 | it "for SDIRK_5_3_4' and BDF" $ maxDiffB < 1.0e-6 | ||
184 | it "for TRBDF2_3_3_2' and BDF" $ maxDiffC < 1.0e-6 | ||
185 | it "for CV and ARK for the Predator Prey model" $ maxDiffPpA < 1.0e-3 | ||
186 | |||
diff --git a/packages/sundials/src/Numeric/Sundials/ARKode/ODE.hs b/packages/sundials/src/Numeric/Sundials/ARKode/ODE.hs deleted file mode 100644 index 48ac887..0000000 --- a/packages/sundials/src/Numeric/Sundials/ARKode/ODE.hs +++ /dev/null | |||
@@ -1,896 +0,0 @@ | |||
1 | {-# LANGUAGE QuasiQuotes #-} | ||
2 | {-# LANGUAGE TemplateHaskell #-} | ||
3 | {-# LANGUAGE MultiWayIf #-} | ||
4 | {-# LANGUAGE OverloadedStrings #-} | ||
5 | {-# LANGUAGE ScopedTypeVariables #-} | ||
6 | {-# LANGUAGE DeriveGeneric #-} | ||
7 | {-# LANGUAGE TypeOperators #-} | ||
8 | {-# LANGUAGE KindSignatures #-} | ||
9 | {-# LANGUAGE TypeSynonymInstances #-} | ||
10 | {-# LANGUAGE FlexibleInstances #-} | ||
11 | {-# LANGUAGE FlexibleContexts #-} | ||
12 | |||
13 | ----------------------------------------------------------------------------- | ||
14 | -- | | ||
15 | -- Module : Numeric.Sundials.ARKode.ODE | ||
16 | -- Copyright : Dominic Steinitz 2018, | ||
17 | -- Novadiscovery 2018 | ||
18 | -- License : BSD | ||
19 | -- Maintainer : Dominic Steinitz | ||
20 | -- Stability : provisional | ||
21 | -- | ||
22 | -- Solution of ordinary differential equation (ODE) initial value problems. | ||
23 | -- See <https://computation.llnl.gov/projects/sundials/sundials-software> for more detail. | ||
24 | -- | ||
25 | -- A simple example: | ||
26 | -- | ||
27 | -- <<diagrams/brusselator.png#diagram=brusselator&height=400&width=500>> | ||
28 | -- | ||
29 | -- @ | ||
30 | -- import Numeric.Sundials.ARKode.ODE | ||
31 | -- import Numeric.LinearAlgebra | ||
32 | -- | ||
33 | -- import Plots as P | ||
34 | -- import qualified Diagrams.Prelude as D | ||
35 | -- import Diagrams.Backend.Rasterific | ||
36 | -- | ||
37 | -- brusselator :: Double -> [Double] -> [Double] | ||
38 | -- brusselator _t x = [ a - (w + 1) * u + v * u * u | ||
39 | -- , w * u - v * u * u | ||
40 | -- , (b - w) / eps - w * u | ||
41 | -- ] | ||
42 | -- where | ||
43 | -- a = 1.0 | ||
44 | -- b = 3.5 | ||
45 | -- eps = 5.0e-6 | ||
46 | -- u = x !! 0 | ||
47 | -- v = x !! 1 | ||
48 | -- w = x !! 2 | ||
49 | -- | ||
50 | -- lSaxis :: [[Double]] -> P.Axis B D.V2 Double | ||
51 | -- lSaxis xs = P.r2Axis &~ do | ||
52 | -- let ts = xs!!0 | ||
53 | -- us = xs!!1 | ||
54 | -- vs = xs!!2 | ||
55 | -- ws = xs!!3 | ||
56 | -- P.linePlot' $ zip ts us | ||
57 | -- P.linePlot' $ zip ts vs | ||
58 | -- P.linePlot' $ zip ts ws | ||
59 | -- | ||
60 | -- main = do | ||
61 | -- let res1 = odeSolve brusselator [1.2, 3.1, 3.0] (fromList [0.0, 0.1 .. 10.0]) | ||
62 | -- renderRasterific "diagrams/brusselator.png" | ||
63 | -- (D.dims2D 500.0 500.0) | ||
64 | -- (renderAxis $ lSaxis $ [0.0, 0.1 .. 10.0]:(toLists $ tr res1)) | ||
65 | -- @ | ||
66 | -- | ||
67 | -- With Sundials ARKode, it is possible to retrieve the Butcher tableau for the solver. | ||
68 | -- | ||
69 | -- @ | ||
70 | -- import Numeric.Sundials.ARKode.ODE | ||
71 | -- import Numeric.LinearAlgebra | ||
72 | -- | ||
73 | -- import Data.List (intercalate) | ||
74 | -- | ||
75 | -- import Text.PrettyPrint.HughesPJClass | ||
76 | -- | ||
77 | -- | ||
78 | -- butcherTableauTex :: ButcherTable -> String | ||
79 | -- butcherTableauTex (ButcherTable m c b b2) = | ||
80 | -- render $ | ||
81 | -- vcat [ text ("\n\\begin{array}{c|" ++ (concat $ replicate n "c") ++ "}") | ||
82 | -- , us | ||
83 | -- , text "\\hline" | ||
84 | -- , text bs <+> text "\\\\" | ||
85 | -- , text b2s <+> text "\\\\" | ||
86 | -- , text "\\end{array}" | ||
87 | -- ] | ||
88 | -- where | ||
89 | -- n = rows m | ||
90 | -- rs = toLists m | ||
91 | -- ss = map (\r -> intercalate " & " $ map show r) rs | ||
92 | -- ts = zipWith (\i r -> show i ++ " & " ++ r) (toList c) ss | ||
93 | -- us = vcat $ map (\r -> text r <+> text "\\\\") ts | ||
94 | -- bs = " & " ++ (intercalate " & " $ map show $ toList b) | ||
95 | -- b2s = " & " ++ (intercalate " & " $ map show $ toList b2) | ||
96 | -- | ||
97 | -- main :: IO () | ||
98 | -- main = do | ||
99 | -- | ||
100 | -- let res = butcherTable (SDIRK_2_1_2 undefined) | ||
101 | -- putStrLn $ show res | ||
102 | -- putStrLn $ butcherTableauTex res | ||
103 | -- | ||
104 | -- let resA = butcherTable (KVAERNO_4_2_3 undefined) | ||
105 | -- putStrLn $ show resA | ||
106 | -- putStrLn $ butcherTableauTex resA | ||
107 | -- | ||
108 | -- let resB = butcherTable (SDIRK_5_3_4 undefined) | ||
109 | -- putStrLn $ show resB | ||
110 | -- putStrLn $ butcherTableauTex resB | ||
111 | -- @ | ||
112 | -- | ||
113 | -- Using the code above from the examples gives | ||
114 | -- | ||
115 | -- KVAERNO_4_2_3 | ||
116 | -- | ||
117 | -- \[ | ||
118 | -- \begin{array}{c|cccc} | ||
119 | -- 0.0 & 0.0 & 0.0 & 0.0 & 0.0 \\ | ||
120 | -- 0.871733043 & 0.4358665215 & 0.4358665215 & 0.0 & 0.0 \\ | ||
121 | -- 1.0 & 0.490563388419108 & 7.3570090080892e-2 & 0.4358665215 & 0.0 \\ | ||
122 | -- 1.0 & 0.308809969973036 & 1.490563388254106 & -1.235239879727145 & 0.4358665215 \\ | ||
123 | -- \hline | ||
124 | -- & 0.308809969973036 & 1.490563388254106 & -1.235239879727145 & 0.4358665215 \\ | ||
125 | -- & 0.490563388419108 & 7.3570090080892e-2 & 0.4358665215 & 0.0 \\ | ||
126 | -- \end{array} | ||
127 | -- \] | ||
128 | -- | ||
129 | -- SDIRK_2_1_2 | ||
130 | -- | ||
131 | -- \[ | ||
132 | -- \begin{array}{c|cc} | ||
133 | -- 1.0 & 1.0 & 0.0 \\ | ||
134 | -- 0.0 & -1.0 & 1.0 \\ | ||
135 | -- \hline | ||
136 | -- & 0.5 & 0.5 \\ | ||
137 | -- & 1.0 & 0.0 \\ | ||
138 | -- \end{array} | ||
139 | -- \] | ||
140 | -- | ||
141 | -- SDIRK_5_3_4 | ||
142 | -- | ||
143 | -- \[ | ||
144 | -- \begin{array}{c|ccccc} | ||
145 | -- 0.25 & 0.25 & 0.0 & 0.0 & 0.0 & 0.0 \\ | ||
146 | -- 0.75 & 0.5 & 0.25 & 0.0 & 0.0 & 0.0 \\ | ||
147 | -- 0.55 & 0.34 & -4.0e-2 & 0.25 & 0.0 & 0.0 \\ | ||
148 | -- 0.5 & 0.2727941176470588 & -5.036764705882353e-2 & 2.7573529411764705e-2 & 0.25 & 0.0 \\ | ||
149 | -- 1.0 & 1.0416666666666667 & -1.0208333333333333 & 7.8125 & -7.083333333333333 & 0.25 \\ | ||
150 | -- \hline | ||
151 | -- & 1.0416666666666667 & -1.0208333333333333 & 7.8125 & -7.083333333333333 & 0.25 \\ | ||
152 | -- & 1.2291666666666667 & -0.17708333333333334 & 7.03125 & -7.083333333333333 & 0.0 \\ | ||
153 | -- \end{array} | ||
154 | -- \] | ||
155 | ----------------------------------------------------------------------------- | ||
156 | module Numeric.Sundials.ARKode.ODE ( odeSolve | ||
157 | , odeSolveV | ||
158 | , odeSolveVWith | ||
159 | , odeSolveVWith' | ||
160 | , ButcherTable(..) | ||
161 | , butcherTable | ||
162 | , ODEMethod(..) | ||
163 | , StepControl(..) | ||
164 | ) where | ||
165 | |||
166 | import qualified Language.C.Inline as C | ||
167 | import qualified Language.C.Inline.Unsafe as CU | ||
168 | |||
169 | import Data.Monoid ((<>)) | ||
170 | import Data.Maybe (isJust) | ||
171 | |||
172 | import Foreign.C.Types (CDouble, CInt, CLong) | ||
173 | import Foreign.Ptr (Ptr) | ||
174 | import Foreign.Storable (poke) | ||
175 | |||
176 | import qualified Data.Vector.Storable as V | ||
177 | |||
178 | import Data.Coerce (coerce) | ||
179 | import System.IO.Unsafe (unsafePerformIO) | ||
180 | import GHC.Generics (C1, Constructor, (:+:)(..), D1, Rep, Generic, M1(..), | ||
181 | from, conName) | ||
182 | |||
183 | import Numeric.LinearAlgebra.Devel (createVector) | ||
184 | |||
185 | import Numeric.LinearAlgebra.HMatrix (Vector, Matrix, toList, rows, | ||
186 | cols, toLists, size, reshape, | ||
187 | subVector, subMatrix, (><)) | ||
188 | |||
189 | import Numeric.Sundials.ODEOpts (ODEOpts(..), Jacobian, SundialsDiagnostics(..)) | ||
190 | import qualified Numeric.Sundials.Arkode as T | ||
191 | import Numeric.Sundials.Arkode (getDataFromContents, putDataInContents, arkSMax, | ||
192 | sDIRK_2_1_2, | ||
193 | bILLINGTON_3_3_2, | ||
194 | tRBDF2_3_3_2, | ||
195 | kVAERNO_4_2_3, | ||
196 | aRK324L2SA_DIRK_4_2_3, | ||
197 | cASH_5_2_4, | ||
198 | cASH_5_3_4, | ||
199 | sDIRK_5_3_4, | ||
200 | kVAERNO_5_3_4, | ||
201 | aRK436L2SA_DIRK_6_3_4, | ||
202 | kVAERNO_7_4_5, | ||
203 | aRK548L2SA_DIRK_8_4_5, | ||
204 | hEUN_EULER_2_1_2, | ||
205 | bOGACKI_SHAMPINE_4_2_3, | ||
206 | aRK324L2SA_ERK_4_2_3, | ||
207 | zONNEVELD_5_3_4, | ||
208 | aRK436L2SA_ERK_6_3_4, | ||
209 | sAYFY_ABURUB_6_3_4, | ||
210 | cASH_KARP_6_4_5, | ||
211 | fEHLBERG_6_4_5, | ||
212 | dORMAND_PRINCE_7_4_5, | ||
213 | aRK548L2SA_ERK_8_4_5, | ||
214 | vERNER_8_5_6, | ||
215 | fEHLBERG_13_7_8) | ||
216 | |||
217 | |||
218 | C.context (C.baseCtx <> C.vecCtx <> C.funCtx <> T.sunCtx) | ||
219 | |||
220 | C.include "<stdlib.h>" | ||
221 | C.include "<stdio.h>" | ||
222 | C.include "<math.h>" | ||
223 | C.include "<arkode/arkode.h>" -- prototypes for ARKODE fcts., consts. | ||
224 | C.include "<nvector/nvector_serial.h>" -- serial N_Vector types, fcts., macros | ||
225 | C.include "<sunmatrix/sunmatrix_dense.h>" -- access to dense SUNMatrix | ||
226 | C.include "<sunlinsol/sunlinsol_dense.h>" -- access to dense SUNLinearSolver | ||
227 | C.include "<arkode/arkode_direct.h>" -- access to ARKDls interface | ||
228 | C.include "<sundials/sundials_types.h>" -- definition of type realtype | ||
229 | C.include "<sundials/sundials_math.h>" | ||
230 | C.include "../../../helpers.h" | ||
231 | C.include "Numeric/Sundials/Arkode_hsc.h" | ||
232 | |||
233 | |||
234 | -- | Stepping functions | ||
235 | data ODEMethod = SDIRK_2_1_2 Jacobian | ||
236 | | SDIRK_2_1_2' | ||
237 | | BILLINGTON_3_3_2 Jacobian | ||
238 | | BILLINGTON_3_3_2' | ||
239 | | TRBDF2_3_3_2 Jacobian | ||
240 | | TRBDF2_3_3_2' | ||
241 | | KVAERNO_4_2_3 Jacobian | ||
242 | | KVAERNO_4_2_3' | ||
243 | | ARK324L2SA_DIRK_4_2_3 Jacobian | ||
244 | | ARK324L2SA_DIRK_4_2_3' | ||
245 | | CASH_5_2_4 Jacobian | ||
246 | | CASH_5_2_4' | ||
247 | | CASH_5_3_4 Jacobian | ||
248 | | CASH_5_3_4' | ||
249 | | SDIRK_5_3_4 Jacobian | ||
250 | | SDIRK_5_3_4' | ||
251 | | KVAERNO_5_3_4 Jacobian | ||
252 | | KVAERNO_5_3_4' | ||
253 | | ARK436L2SA_DIRK_6_3_4 Jacobian | ||
254 | | ARK436L2SA_DIRK_6_3_4' | ||
255 | | KVAERNO_7_4_5 Jacobian | ||
256 | | KVAERNO_7_4_5' | ||
257 | | ARK548L2SA_DIRK_8_4_5 Jacobian | ||
258 | | ARK548L2SA_DIRK_8_4_5' | ||
259 | | HEUN_EULER_2_1_2 Jacobian | ||
260 | | HEUN_EULER_2_1_2' | ||
261 | | BOGACKI_SHAMPINE_4_2_3 Jacobian | ||
262 | | BOGACKI_SHAMPINE_4_2_3' | ||
263 | | ARK324L2SA_ERK_4_2_3 Jacobian | ||
264 | | ARK324L2SA_ERK_4_2_3' | ||
265 | | ZONNEVELD_5_3_4 Jacobian | ||
266 | | ZONNEVELD_5_3_4' | ||
267 | | ARK436L2SA_ERK_6_3_4 Jacobian | ||
268 | | ARK436L2SA_ERK_6_3_4' | ||
269 | | SAYFY_ABURUB_6_3_4 Jacobian | ||
270 | | SAYFY_ABURUB_6_3_4' | ||
271 | | CASH_KARP_6_4_5 Jacobian | ||
272 | | CASH_KARP_6_4_5' | ||
273 | | FEHLBERG_6_4_5 Jacobian | ||
274 | | FEHLBERG_6_4_5' | ||
275 | | DORMAND_PRINCE_7_4_5 Jacobian | ||
276 | | DORMAND_PRINCE_7_4_5' | ||
277 | | ARK548L2SA_ERK_8_4_5 Jacobian | ||
278 | | ARK548L2SA_ERK_8_4_5' | ||
279 | | VERNER_8_5_6 Jacobian | ||
280 | | VERNER_8_5_6' | ||
281 | | FEHLBERG_13_7_8 Jacobian | ||
282 | | FEHLBERG_13_7_8' | ||
283 | deriving Generic | ||
284 | |||
285 | constrName :: (HasConstructor (Rep a), Generic a)=> a -> String | ||
286 | constrName = genericConstrName . from | ||
287 | |||
288 | class HasConstructor (f :: * -> *) where | ||
289 | genericConstrName :: f x -> String | ||
290 | |||
291 | instance HasConstructor f => HasConstructor (D1 c f) where | ||
292 | genericConstrName (M1 x) = genericConstrName x | ||
293 | |||
294 | instance (HasConstructor x, HasConstructor y) => HasConstructor (x :+: y) where | ||
295 | genericConstrName (L1 l) = genericConstrName l | ||
296 | genericConstrName (R1 r) = genericConstrName r | ||
297 | |||
298 | instance Constructor c => HasConstructor (C1 c f) where | ||
299 | genericConstrName x = conName x | ||
300 | |||
301 | instance Show ODEMethod where | ||
302 | show x = constrName x | ||
303 | |||
304 | -- FIXME: We can probably do better here with generics | ||
305 | getMethod :: ODEMethod -> Int | ||
306 | getMethod (SDIRK_2_1_2 _) = sDIRK_2_1_2 | ||
307 | getMethod (SDIRK_2_1_2') = sDIRK_2_1_2 | ||
308 | getMethod (BILLINGTON_3_3_2 _) = bILLINGTON_3_3_2 | ||
309 | getMethod (BILLINGTON_3_3_2') = bILLINGTON_3_3_2 | ||
310 | getMethod (TRBDF2_3_3_2 _) = tRBDF2_3_3_2 | ||
311 | getMethod (TRBDF2_3_3_2') = tRBDF2_3_3_2 | ||
312 | getMethod (KVAERNO_4_2_3 _) = kVAERNO_4_2_3 | ||
313 | getMethod (KVAERNO_4_2_3') = kVAERNO_4_2_3 | ||
314 | getMethod (ARK324L2SA_DIRK_4_2_3 _) = aRK324L2SA_DIRK_4_2_3 | ||
315 | getMethod (ARK324L2SA_DIRK_4_2_3') = aRK324L2SA_DIRK_4_2_3 | ||
316 | getMethod (CASH_5_2_4 _) = cASH_5_2_4 | ||
317 | getMethod (CASH_5_2_4') = cASH_5_2_4 | ||
318 | getMethod (CASH_5_3_4 _) = cASH_5_3_4 | ||
319 | getMethod (CASH_5_3_4') = cASH_5_3_4 | ||
320 | getMethod (SDIRK_5_3_4 _) = sDIRK_5_3_4 | ||
321 | getMethod (SDIRK_5_3_4') = sDIRK_5_3_4 | ||
322 | getMethod (KVAERNO_5_3_4 _) = kVAERNO_5_3_4 | ||
323 | getMethod (KVAERNO_5_3_4') = kVAERNO_5_3_4 | ||
324 | getMethod (ARK436L2SA_DIRK_6_3_4 _) = aRK436L2SA_DIRK_6_3_4 | ||
325 | getMethod (ARK436L2SA_DIRK_6_3_4') = aRK436L2SA_DIRK_6_3_4 | ||
326 | getMethod (KVAERNO_7_4_5 _) = kVAERNO_7_4_5 | ||
327 | getMethod (KVAERNO_7_4_5') = kVAERNO_7_4_5 | ||
328 | getMethod (ARK548L2SA_DIRK_8_4_5 _) = aRK548L2SA_DIRK_8_4_5 | ||
329 | getMethod (ARK548L2SA_DIRK_8_4_5') = aRK548L2SA_DIRK_8_4_5 | ||
330 | getMethod (HEUN_EULER_2_1_2 _) = hEUN_EULER_2_1_2 | ||
331 | getMethod (HEUN_EULER_2_1_2') = hEUN_EULER_2_1_2 | ||
332 | getMethod (BOGACKI_SHAMPINE_4_2_3 _) = bOGACKI_SHAMPINE_4_2_3 | ||
333 | getMethod (BOGACKI_SHAMPINE_4_2_3') = bOGACKI_SHAMPINE_4_2_3 | ||
334 | getMethod (ARK324L2SA_ERK_4_2_3 _) = aRK324L2SA_ERK_4_2_3 | ||
335 | getMethod (ARK324L2SA_ERK_4_2_3') = aRK324L2SA_ERK_4_2_3 | ||
336 | getMethod (ZONNEVELD_5_3_4 _) = zONNEVELD_5_3_4 | ||
337 | getMethod (ZONNEVELD_5_3_4') = zONNEVELD_5_3_4 | ||
338 | getMethod (ARK436L2SA_ERK_6_3_4 _) = aRK436L2SA_ERK_6_3_4 | ||
339 | getMethod (ARK436L2SA_ERK_6_3_4') = aRK436L2SA_ERK_6_3_4 | ||
340 | getMethod (SAYFY_ABURUB_6_3_4 _) = sAYFY_ABURUB_6_3_4 | ||
341 | getMethod (SAYFY_ABURUB_6_3_4') = sAYFY_ABURUB_6_3_4 | ||
342 | getMethod (CASH_KARP_6_4_5 _) = cASH_KARP_6_4_5 | ||
343 | getMethod (CASH_KARP_6_4_5') = cASH_KARP_6_4_5 | ||
344 | getMethod (FEHLBERG_6_4_5 _) = fEHLBERG_6_4_5 | ||
345 | getMethod (FEHLBERG_6_4_5' ) = fEHLBERG_6_4_5 | ||
346 | getMethod (DORMAND_PRINCE_7_4_5 _) = dORMAND_PRINCE_7_4_5 | ||
347 | getMethod (DORMAND_PRINCE_7_4_5') = dORMAND_PRINCE_7_4_5 | ||
348 | getMethod (ARK548L2SA_ERK_8_4_5 _) = aRK548L2SA_ERK_8_4_5 | ||
349 | getMethod (ARK548L2SA_ERK_8_4_5') = aRK548L2SA_ERK_8_4_5 | ||
350 | getMethod (VERNER_8_5_6 _) = vERNER_8_5_6 | ||
351 | getMethod (VERNER_8_5_6') = vERNER_8_5_6 | ||
352 | getMethod (FEHLBERG_13_7_8 _) = fEHLBERG_13_7_8 | ||
353 | getMethod (FEHLBERG_13_7_8') = fEHLBERG_13_7_8 | ||
354 | |||
355 | getJacobian :: ODEMethod -> Maybe Jacobian | ||
356 | getJacobian (SDIRK_2_1_2 j) = Just j | ||
357 | getJacobian (BILLINGTON_3_3_2 j) = Just j | ||
358 | getJacobian (TRBDF2_3_3_2 j) = Just j | ||
359 | getJacobian (KVAERNO_4_2_3 j) = Just j | ||
360 | getJacobian (ARK324L2SA_DIRK_4_2_3 j) = Just j | ||
361 | getJacobian (CASH_5_2_4 j) = Just j | ||
362 | getJacobian (CASH_5_3_4 j) = Just j | ||
363 | getJacobian (SDIRK_5_3_4 j) = Just j | ||
364 | getJacobian (KVAERNO_5_3_4 j) = Just j | ||
365 | getJacobian (ARK436L2SA_DIRK_6_3_4 j) = Just j | ||
366 | getJacobian (KVAERNO_7_4_5 j) = Just j | ||
367 | getJacobian (ARK548L2SA_DIRK_8_4_5 j) = Just j | ||
368 | getJacobian (HEUN_EULER_2_1_2 j) = Just j | ||
369 | getJacobian (BOGACKI_SHAMPINE_4_2_3 j) = Just j | ||
370 | getJacobian (ARK324L2SA_ERK_4_2_3 j) = Just j | ||
371 | getJacobian (ZONNEVELD_5_3_4 j) = Just j | ||
372 | getJacobian (ARK436L2SA_ERK_6_3_4 j) = Just j | ||
373 | getJacobian (SAYFY_ABURUB_6_3_4 j) = Just j | ||
374 | getJacobian (CASH_KARP_6_4_5 j) = Just j | ||
375 | getJacobian (FEHLBERG_6_4_5 j) = Just j | ||
376 | getJacobian (DORMAND_PRINCE_7_4_5 j) = Just j | ||
377 | getJacobian (ARK548L2SA_ERK_8_4_5 j) = Just j | ||
378 | getJacobian (VERNER_8_5_6 j) = Just j | ||
379 | getJacobian (FEHLBERG_13_7_8 j) = Just j | ||
380 | getJacobian _ = Nothing | ||
381 | |||
382 | -- | A version of 'odeSolveVWith' with reasonable default step control. | ||
383 | odeSolveV | ||
384 | :: ODEMethod | ||
385 | -> Maybe Double -- ^ initial step size - by default, ARKode | ||
386 | -- estimates the initial step size to be the | ||
387 | -- solution \(h\) of the equation | ||
388 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
389 | -- \(\ddot{y}\) is an estimated value of the | ||
390 | -- second derivative of the solution at \(t_0\) | ||
391 | -> Double -- ^ absolute tolerance for the state vector | ||
392 | -> Double -- ^ relative tolerance for the state vector | ||
393 | -> (Double -> Vector Double -> Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
394 | -> Vector Double -- ^ initial conditions | ||
395 | -> Vector Double -- ^ desired solution times | ||
396 | -> Matrix Double -- ^ solution | ||
397 | odeSolveV meth hi epsAbs epsRel f y0 ts = | ||
398 | odeSolveVWith meth (X epsAbs epsRel) hi g y0 ts | ||
399 | where | ||
400 | g t x0 = coerce $ f t x0 | ||
401 | |||
402 | -- | A version of 'odeSolveV' with reasonable default parameters and | ||
403 | -- system of equations defined using lists. FIXME: we should say | ||
404 | -- something about the fact we could use the Jacobian but don't for | ||
405 | -- compatibility with hmatrix-gsl. | ||
406 | odeSolve :: (Double -> [Double] -> [Double]) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
407 | -> [Double] -- ^ initial conditions | ||
408 | -> Vector Double -- ^ desired solution times | ||
409 | -> Matrix Double -- ^ solution | ||
410 | odeSolve f y0 ts = | ||
411 | -- FIXME: These tolerances are different from the ones in GSL | ||
412 | odeSolveVWith SDIRK_5_3_4' (XX' 1.0e-6 1.0e-10 1 1) Nothing g (V.fromList y0) (V.fromList $ toList ts) | ||
413 | where | ||
414 | g t x0 = V.fromList $ f t (V.toList x0) | ||
415 | |||
416 | odeSolveVWith :: | ||
417 | ODEMethod | ||
418 | -> StepControl | ||
419 | -> Maybe Double -- ^ initial step size - by default, ARKode | ||
420 | -- estimates the initial step size to be the | ||
421 | -- solution \(h\) of the equation | ||
422 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
423 | -- \(\ddot{y}\) is an estimated value of the second | ||
424 | -- derivative of the solution at \(t_0\) | ||
425 | -> (Double -> V.Vector Double -> V.Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
426 | -> V.Vector Double -- ^ Initial conditions | ||
427 | -> V.Vector Double -- ^ Desired solution times | ||
428 | -> Matrix Double -- ^ Error code or solution | ||
429 | odeSolveVWith method control initStepSize f y0 tt = | ||
430 | case odeSolveVWith' opts method control initStepSize f y0 tt of | ||
431 | Left (c, _v) -> error $ show c -- FIXME | ||
432 | Right (v, _d) -> v | ||
433 | where | ||
434 | opts = ODEOpts { maxNumSteps = 10000 | ||
435 | , minStep = 1.0e-12 | ||
436 | , relTol = error "relTol" | ||
437 | , absTols = error "absTol" | ||
438 | , initStep = error "initStep" | ||
439 | , maxFail = 10 | ||
440 | } | ||
441 | |||
442 | odeSolveVWith' :: | ||
443 | ODEOpts | ||
444 | -> ODEMethod | ||
445 | -> StepControl | ||
446 | -> Maybe Double -- ^ initial step size - by default, ARKode | ||
447 | -- estimates the initial step size to be the | ||
448 | -- solution \(h\) of the equation | ||
449 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
450 | -- \(\ddot{y}\) is an estimated value of the second | ||
451 | -- derivative of the solution at \(t_0\) | ||
452 | -> (Double -> V.Vector Double -> V.Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
453 | -> V.Vector Double -- ^ Initial conditions | ||
454 | -> V.Vector Double -- ^ Desired solution times | ||
455 | -> Either (Matrix Double, Int) (Matrix Double, SundialsDiagnostics) -- ^ Error code or solution | ||
456 | odeSolveVWith' opts method control initStepSize f y0 tt = | ||
457 | case solveOdeC (fromIntegral $ maxFail opts) | ||
458 | (fromIntegral $ maxNumSteps opts) (coerce $ minStep opts) | ||
459 | (fromIntegral $ getMethod method) (coerce initStepSize) jacH (scise control) | ||
460 | (coerce f) (coerce y0) (coerce tt) of | ||
461 | Left (v, c) -> Left (reshape l (coerce v), fromIntegral c) | ||
462 | Right (v, d) -> Right (reshape l (coerce v), d) | ||
463 | where | ||
464 | l = size y0 | ||
465 | scise (X aTol rTol) = coerce (V.replicate l aTol, rTol) | ||
466 | scise (X' aTol rTol) = coerce (V.replicate l aTol, rTol) | ||
467 | scise (XX' aTol rTol yScale _yDotScale) = coerce (V.replicate l aTol, yScale * rTol) | ||
468 | -- FIXME; Should we check that the length of ss is correct? | ||
469 | scise (ScXX' aTol rTol yScale _yDotScale ss) = coerce (V.map (* aTol) ss, yScale * rTol) | ||
470 | jacH = fmap (\g t v -> matrixToSunMatrix $ g (coerce t) (coerce v)) $ | ||
471 | getJacobian method | ||
472 | matrixToSunMatrix m = T.SunMatrix { T.rows = nr, T.cols = nc, T.vals = vs } | ||
473 | where | ||
474 | nr = fromIntegral $ rows m | ||
475 | nc = fromIntegral $ cols m | ||
476 | -- FIXME: efficiency | ||
477 | vs = V.fromList $ map coerce $ concat $ toLists m | ||
478 | |||
479 | solveOdeC :: | ||
480 | CInt -> | ||
481 | CLong -> | ||
482 | CDouble -> | ||
483 | CInt -> | ||
484 | Maybe CDouble -> | ||
485 | (Maybe (CDouble -> V.Vector CDouble -> T.SunMatrix)) -> | ||
486 | (V.Vector CDouble, CDouble) -> | ||
487 | (CDouble -> V.Vector CDouble -> V.Vector CDouble) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
488 | -> V.Vector CDouble -- ^ Initial conditions | ||
489 | -> V.Vector CDouble -- ^ Desired solution times | ||
490 | -> Either (V.Vector CDouble, CInt) (V.Vector CDouble, SundialsDiagnostics) -- ^ Partial solution and error code or | ||
491 | -- solution and diagnostics | ||
492 | solveOdeC maxErrTestFails maxNumSteps_ minStep_ method initStepSize | ||
493 | jacH (aTols, rTol) fun f0 ts = unsafePerformIO $ do | ||
494 | |||
495 | let isInitStepSize :: CInt | ||
496 | isInitStepSize = fromIntegral $ fromEnum $ isJust initStepSize | ||
497 | ss :: CDouble | ||
498 | ss = case initStepSize of | ||
499 | -- It would be better to put an error message here but | ||
500 | -- inline-c seems to evaluate this even if it is never | ||
501 | -- used :( | ||
502 | Nothing -> 0.0 | ||
503 | Just x -> x | ||
504 | |||
505 | let dim = V.length f0 | ||
506 | nEq :: CLong | ||
507 | nEq = fromIntegral dim | ||
508 | nTs :: CInt | ||
509 | nTs = fromIntegral $ V.length ts | ||
510 | quasiMatrixRes <- createVector ((fromIntegral dim) * (fromIntegral nTs)) | ||
511 | qMatMut <- V.thaw quasiMatrixRes | ||
512 | diagnostics :: V.Vector CLong <- createVector 10 -- FIXME | ||
513 | diagMut <- V.thaw diagnostics | ||
514 | -- We need the types that sundials expects. These are tied together | ||
515 | -- in 'CLangToHaskellTypes'. FIXME: The Haskell type is currently empty! | ||
516 | let funIO :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr () -> IO CInt | ||
517 | funIO x y f _ptr = do | ||
518 | -- Convert the pointer we get from C (y) to a vector, and then | ||
519 | -- apply the user-supplied function. | ||
520 | fImm <- fun x <$> getDataFromContents dim y | ||
521 | -- Fill in the provided pointer with the resulting vector. | ||
522 | putDataInContents fImm dim f | ||
523 | -- FIXME: I don't understand what this comment means | ||
524 | -- Unsafe since the function will be called many times. | ||
525 | [CU.exp| int{ 0 } |] | ||
526 | let isJac :: CInt | ||
527 | isJac = fromIntegral $ fromEnum $ isJust jacH | ||
528 | jacIO :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr T.SunMatrix -> | ||
529 | Ptr () -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr T.SunVector -> | ||
530 | IO CInt | ||
531 | jacIO t y _fy jacS _ptr _tmp1 _tmp2 _tmp3 = do | ||
532 | case jacH of | ||
533 | Nothing -> error "Numeric.Sundials.ARKode.ODE: Jacobian not defined" | ||
534 | Just jacI -> do j <- jacI t <$> getDataFromContents dim y | ||
535 | poke jacS j | ||
536 | -- FIXME: I don't understand what this comment means | ||
537 | -- Unsafe since the function will be called many times. | ||
538 | [CU.exp| int{ 0 } |] | ||
539 | |||
540 | res <- [C.block| int { | ||
541 | /* general problem variables */ | ||
542 | |||
543 | int flag; /* reusable error-checking flag */ | ||
544 | int i, j; /* reusable loop indices */ | ||
545 | N_Vector y = NULL; /* empty vector for storing solution */ | ||
546 | N_Vector tv = NULL; /* empty vector for storing absolute tolerances */ | ||
547 | SUNMatrix A = NULL; /* empty matrix for linear solver */ | ||
548 | SUNLinearSolver LS = NULL; /* empty linear solver object */ | ||
549 | void *arkode_mem = NULL; /* empty ARKode memory structure */ | ||
550 | realtype t; | ||
551 | long int nst, nst_a, nfe, nfi, nsetups, nje, nfeLS, nni, ncfn, netf; | ||
552 | |||
553 | /* general problem parameters */ | ||
554 | |||
555 | realtype T0 = RCONST(($vec-ptr:(double *ts))[0]); /* initial time */ | ||
556 | sunindextype NEQ = $(sunindextype nEq); /* number of dependent vars. */ | ||
557 | |||
558 | /* Initialize data structures */ | ||
559 | |||
560 | y = N_VNew_Serial(NEQ); /* Create serial vector for solution */ | ||
561 | if (check_flag((void *)y, "N_VNew_Serial", 0)) return 1; | ||
562 | /* Specify initial condition */ | ||
563 | for (i = 0; i < NEQ; i++) { | ||
564 | NV_Ith_S(y,i) = ($vec-ptr:(double *f0))[i]; | ||
565 | }; | ||
566 | |||
567 | tv = N_VNew_Serial(NEQ); /* Create serial vector for absolute tolerances */ | ||
568 | if (check_flag((void *)tv, "N_VNew_Serial", 0)) return 1; | ||
569 | /* Specify tolerances */ | ||
570 | for (i = 0; i < NEQ; i++) { | ||
571 | NV_Ith_S(tv,i) = ($vec-ptr:(double *aTols))[i]; | ||
572 | }; | ||
573 | |||
574 | arkode_mem = ARKodeCreate(); /* Create the solver memory */ | ||
575 | if (check_flag((void *)arkode_mem, "ARKodeCreate", 0)) return 1; | ||
576 | |||
577 | /* Call ARKodeInit to initialize the integrator memory and specify the */ | ||
578 | /* right-hand side function in y'=f(t,y), the inital time T0, and */ | ||
579 | /* the initial dependent variable vector y. Note: we treat the */ | ||
580 | /* problem as fully implicit and set f_E to NULL and f_I to f. */ | ||
581 | |||
582 | /* Here we use the C types defined in helpers.h which tie up with */ | ||
583 | /* the Haskell types defined in CLangToHaskellTypes */ | ||
584 | if ($(int method) < MIN_DIRK_NUM) { | ||
585 | flag = ARKodeInit(arkode_mem, $fun:(int (* funIO) (double t, SunVector y[], SunVector dydt[], void * params)), NULL, T0, y); | ||
586 | if (check_flag(&flag, "ARKodeInit", 1)) return 1; | ||
587 | } else { | ||
588 | flag = ARKodeInit(arkode_mem, NULL, $fun:(int (* funIO) (double t, SunVector y[], SunVector dydt[], void * params)), T0, y); | ||
589 | if (check_flag(&flag, "ARKodeInit", 1)) return 1; | ||
590 | } | ||
591 | |||
592 | flag = ARKodeSetMinStep(arkode_mem, $(double minStep_)); | ||
593 | if (check_flag(&flag, "ARKodeSetMinStep", 1)) return 1; | ||
594 | flag = ARKodeSetMaxNumSteps(arkode_mem, $(long int maxNumSteps_)); | ||
595 | if (check_flag(&flag, "ARKodeSetMaxNumSteps", 1)) return 1; | ||
596 | flag = ARKodeSetMaxErrTestFails(arkode_mem, $(int maxErrTestFails)); | ||
597 | if (check_flag(&flag, "ARKodeSetMaxErrTestFails", 1)) return 1; | ||
598 | |||
599 | /* Set routines */ | ||
600 | flag = ARKodeSVtolerances(arkode_mem, $(double rTol), tv); | ||
601 | if (check_flag(&flag, "ARKodeSVtolerances", 1)) return 1; | ||
602 | |||
603 | /* Initialize dense matrix data structure and solver */ | ||
604 | A = SUNDenseMatrix(NEQ, NEQ); | ||
605 | if (check_flag((void *)A, "SUNDenseMatrix", 0)) return 1; | ||
606 | LS = SUNDenseLinearSolver(y, A); | ||
607 | if (check_flag((void *)LS, "SUNDenseLinearSolver", 0)) return 1; | ||
608 | |||
609 | /* Attach matrix and linear solver */ | ||
610 | flag = ARKDlsSetLinearSolver(arkode_mem, LS, A); | ||
611 | if (check_flag(&flag, "ARKDlsSetLinearSolver", 1)) return 1; | ||
612 | |||
613 | /* Set the initial step size if there is one */ | ||
614 | if ($(int isInitStepSize)) { | ||
615 | /* FIXME: We could check if the initial step size is 0 */ | ||
616 | /* or even NaN and then throw an error */ | ||
617 | flag = ARKodeSetInitStep(arkode_mem, $(double ss)); | ||
618 | if (check_flag(&flag, "ARKodeSetInitStep", 1)) return 1; | ||
619 | } | ||
620 | |||
621 | /* Set the Jacobian if there is one */ | ||
622 | if ($(int isJac)) { | ||
623 | flag = ARKDlsSetJacFn(arkode_mem, $fun:(int (* jacIO) (double t, SunVector y[], SunVector fy[], SunMatrix Jac[], void * params, SunVector tmp1[], SunVector tmp2[], SunVector tmp3[]))); | ||
624 | if (check_flag(&flag, "ARKDlsSetJacFn", 1)) return 1; | ||
625 | } | ||
626 | |||
627 | /* Store initial conditions */ | ||
628 | for (j = 0; j < NEQ; j++) { | ||
629 | ($vec-ptr:(double *qMatMut))[0 * $(int nTs) + j] = NV_Ith_S(y,j); | ||
630 | } | ||
631 | |||
632 | /* Explicitly set the method */ | ||
633 | if ($(int method) >= MIN_DIRK_NUM) { | ||
634 | flag = ARKodeSetIRKTableNum(arkode_mem, $(int method)); | ||
635 | if (check_flag(&flag, "ARKodeSetIRKTableNum", 1)) return 1; | ||
636 | } else { | ||
637 | flag = ARKodeSetERKTableNum(arkode_mem, $(int method)); | ||
638 | if (check_flag(&flag, "ARKodeSetERKTableNum", 1)) return 1; | ||
639 | } | ||
640 | |||
641 | /* Main time-stepping loop: calls ARKode to perform the integration */ | ||
642 | /* Stops when the final time has been reached */ | ||
643 | for (i = 1; i < $(int nTs); i++) { | ||
644 | |||
645 | flag = ARKode(arkode_mem, ($vec-ptr:(double *ts))[i], y, &t, ARK_NORMAL); /* call integrator */ | ||
646 | if (check_flag(&flag, "ARKode solver failure, stopping integration", 1)) return 1; | ||
647 | |||
648 | /* Store the results for Haskell */ | ||
649 | for (j = 0; j < NEQ; j++) { | ||
650 | ($vec-ptr:(double *qMatMut))[i * NEQ + j] = NV_Ith_S(y,j); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* Get some final statistics on how the solve progressed */ | ||
655 | |||
656 | flag = ARKodeGetNumSteps(arkode_mem, &nst); | ||
657 | check_flag(&flag, "ARKodeGetNumSteps", 1); | ||
658 | ($vec-ptr:(long int *diagMut))[0] = nst; | ||
659 | |||
660 | flag = ARKodeGetNumStepAttempts(arkode_mem, &nst_a); | ||
661 | check_flag(&flag, "ARKodeGetNumStepAttempts", 1); | ||
662 | ($vec-ptr:(long int *diagMut))[1] = nst_a; | ||
663 | |||
664 | flag = ARKodeGetNumRhsEvals(arkode_mem, &nfe, &nfi); | ||
665 | check_flag(&flag, "ARKodeGetNumRhsEvals", 1); | ||
666 | ($vec-ptr:(long int *diagMut))[2] = nfe; | ||
667 | ($vec-ptr:(long int *diagMut))[3] = nfi; | ||
668 | |||
669 | flag = ARKodeGetNumLinSolvSetups(arkode_mem, &nsetups); | ||
670 | check_flag(&flag, "ARKodeGetNumLinSolvSetups", 1); | ||
671 | ($vec-ptr:(long int *diagMut))[4] = nsetups; | ||
672 | |||
673 | flag = ARKodeGetNumErrTestFails(arkode_mem, &netf); | ||
674 | check_flag(&flag, "ARKodeGetNumErrTestFails", 1); | ||
675 | ($vec-ptr:(long int *diagMut))[5] = netf; | ||
676 | |||
677 | flag = ARKodeGetNumNonlinSolvIters(arkode_mem, &nni); | ||
678 | check_flag(&flag, "ARKodeGetNumNonlinSolvIters", 1); | ||
679 | ($vec-ptr:(long int *diagMut))[6] = nni; | ||
680 | |||
681 | flag = ARKodeGetNumNonlinSolvConvFails(arkode_mem, &ncfn); | ||
682 | check_flag(&flag, "ARKodeGetNumNonlinSolvConvFails", 1); | ||
683 | ($vec-ptr:(long int *diagMut))[7] = ncfn; | ||
684 | |||
685 | flag = ARKDlsGetNumJacEvals(arkode_mem, &nje); | ||
686 | check_flag(&flag, "ARKDlsGetNumJacEvals", 1); | ||
687 | ($vec-ptr:(long int *diagMut))[8] = ncfn; | ||
688 | |||
689 | flag = ARKDlsGetNumRhsEvals(arkode_mem, &nfeLS); | ||
690 | check_flag(&flag, "ARKDlsGetNumRhsEvals", 1); | ||
691 | ($vec-ptr:(long int *diagMut))[9] = ncfn; | ||
692 | |||
693 | /* Clean up and return */ | ||
694 | N_VDestroy(y); /* Free y vector */ | ||
695 | N_VDestroy(tv); /* Free tv vector */ | ||
696 | ARKodeFree(&arkode_mem); /* Free integrator memory */ | ||
697 | SUNLinSolFree(LS); /* Free linear solver */ | ||
698 | SUNMatDestroy(A); /* Free A matrix */ | ||
699 | |||
700 | return flag; | ||
701 | } |] | ||
702 | preD <- V.freeze diagMut | ||
703 | let d = SundialsDiagnostics (fromIntegral $ preD V.!0) | ||
704 | (fromIntegral $ preD V.!1) | ||
705 | (fromIntegral $ preD V.!2) | ||
706 | (fromIntegral $ preD V.!3) | ||
707 | (fromIntegral $ preD V.!4) | ||
708 | (fromIntegral $ preD V.!5) | ||
709 | (fromIntegral $ preD V.!6) | ||
710 | (fromIntegral $ preD V.!7) | ||
711 | (fromIntegral $ preD V.!8) | ||
712 | (fromIntegral $ preD V.!9) | ||
713 | m <- V.freeze qMatMut | ||
714 | if res == 0 | ||
715 | then do | ||
716 | return $ Right (m, d) | ||
717 | else do | ||
718 | return $ Left (m, res) | ||
719 | |||
720 | data ButcherTable = ButcherTable { am :: Matrix Double | ||
721 | , cv :: Vector Double | ||
722 | , bv :: Vector Double | ||
723 | , b2v :: Vector Double | ||
724 | } | ||
725 | deriving Show | ||
726 | |||
727 | data ButcherTable' a = ButcherTable' { am' :: V.Vector a | ||
728 | , cv' :: V.Vector a | ||
729 | , bv' :: V.Vector a | ||
730 | , b2v' :: V.Vector a | ||
731 | } | ||
732 | deriving Show | ||
733 | |||
734 | butcherTable :: ODEMethod -> ButcherTable | ||
735 | butcherTable method = | ||
736 | case getBT method of | ||
737 | Left c -> error $ show c -- FIXME | ||
738 | Right (ButcherTable' v w x y, sqp) -> | ||
739 | ButcherTable { am = subMatrix (0, 0) (s, s) $ (arkSMax >< arkSMax) (V.toList v) | ||
740 | , cv = subVector 0 s w | ||
741 | , bv = subVector 0 s x | ||
742 | , b2v = subVector 0 s y | ||
743 | } | ||
744 | where | ||
745 | s = fromIntegral $ sqp V.! 0 | ||
746 | |||
747 | getBT :: ODEMethod -> Either Int (ButcherTable' Double, V.Vector Int) | ||
748 | getBT method = case getButcherTable method of | ||
749 | Left c -> | ||
750 | Left $ fromIntegral c | ||
751 | Right (ButcherTable' a b c d, sqp) -> | ||
752 | Right $ ( ButcherTable' (coerce a) (coerce b) (coerce c) (coerce d) | ||
753 | , V.map fromIntegral sqp ) | ||
754 | |||
755 | getButcherTable :: ODEMethod | ||
756 | -> Either CInt (ButcherTable' CDouble, V.Vector CInt) | ||
757 | getButcherTable method = unsafePerformIO $ do | ||
758 | -- ARKode seems to want an ODE in order to set and then get the | ||
759 | -- Butcher tableau so here's one to keep it happy | ||
760 | let funI :: CDouble -> V.Vector CDouble -> V.Vector CDouble | ||
761 | funI _t ys = V.fromList [ ys V.! 0 ] | ||
762 | let funE :: CDouble -> V.Vector CDouble -> V.Vector CDouble | ||
763 | funE _t ys = V.fromList [ ys V.! 0 ] | ||
764 | f0 = V.fromList [ 1.0 ] | ||
765 | ts = V.fromList [ 0.0 ] | ||
766 | dim = V.length f0 | ||
767 | nEq :: CLong | ||
768 | nEq = fromIntegral dim | ||
769 | mN :: CInt | ||
770 | mN = fromIntegral $ getMethod method | ||
771 | |||
772 | btSQP :: V.Vector CInt <- createVector 3 | ||
773 | btSQPMut <- V.thaw btSQP | ||
774 | btAs :: V.Vector CDouble <- createVector (arkSMax * arkSMax) | ||
775 | btAsMut <- V.thaw btAs | ||
776 | btCs :: V.Vector CDouble <- createVector arkSMax | ||
777 | btBs :: V.Vector CDouble <- createVector arkSMax | ||
778 | btB2s :: V.Vector CDouble <- createVector arkSMax | ||
779 | btCsMut <- V.thaw btCs | ||
780 | btBsMut <- V.thaw btBs | ||
781 | btB2sMut <- V.thaw btB2s | ||
782 | let funIOI :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr () -> IO CInt | ||
783 | funIOI x y f _ptr = do | ||
784 | fImm <- funI x <$> getDataFromContents dim y | ||
785 | putDataInContents fImm dim f | ||
786 | -- FIXME: I don't understand what this comment means | ||
787 | -- Unsafe since the function will be called many times. | ||
788 | [CU.exp| int{ 0 } |] | ||
789 | let funIOE :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr () -> IO CInt | ||
790 | funIOE x y f _ptr = do | ||
791 | fImm <- funE x <$> getDataFromContents dim y | ||
792 | putDataInContents fImm dim f | ||
793 | -- FIXME: I don't understand what this comment means | ||
794 | -- Unsafe since the function will be called many times. | ||
795 | [CU.exp| int{ 0 } |] | ||
796 | res <- [C.block| int { | ||
797 | /* general problem variables */ | ||
798 | |||
799 | int flag; /* reusable error-checking flag */ | ||
800 | N_Vector y = NULL; /* empty vector for storing solution */ | ||
801 | void *arkode_mem = NULL; /* empty ARKode memory structure */ | ||
802 | int i, j; /* reusable loop indices */ | ||
803 | |||
804 | /* general problem parameters */ | ||
805 | |||
806 | realtype T0 = RCONST(($vec-ptr:(double *ts))[0]); /* initial time */ | ||
807 | sunindextype NEQ = $(sunindextype nEq); /* number of dependent vars */ | ||
808 | |||
809 | /* Initialize data structures */ | ||
810 | |||
811 | y = N_VNew_Serial(NEQ); /* Create serial vector for solution */ | ||
812 | if (check_flag((void *)y, "N_VNew_Serial", 0)) return 1; | ||
813 | /* Specify initial condition */ | ||
814 | for (i = 0; i < NEQ; i++) { | ||
815 | NV_Ith_S(y,i) = ($vec-ptr:(double *f0))[i]; | ||
816 | }; | ||
817 | arkode_mem = ARKodeCreate(); /* Create the solver memory */ | ||
818 | if (check_flag((void *)arkode_mem, "ARKodeCreate", 0)) return 1; | ||
819 | |||
820 | flag = ARKodeInit(arkode_mem, $fun:(int (* funIOE) (double t, SunVector y[], SunVector dydt[], void * params)), $fun:(int (* funIOI) (double t, SunVector y[], SunVector dydt[], void * params)), T0, y); | ||
821 | if (check_flag(&flag, "ARKodeInit", 1)) return 1; | ||
822 | |||
823 | if ($(int mN) >= MIN_DIRK_NUM) { | ||
824 | flag = ARKodeSetIRKTableNum(arkode_mem, $(int mN)); | ||
825 | if (check_flag(&flag, "ARKodeSetIRKTableNum", 1)) return 1; | ||
826 | } else { | ||
827 | flag = ARKodeSetERKTableNum(arkode_mem, $(int mN)); | ||
828 | if (check_flag(&flag, "ARKodeSetERKTableNum", 1)) return 1; | ||
829 | } | ||
830 | |||
831 | int s, q, p; | ||
832 | realtype *ai = (realtype *)malloc(ARK_S_MAX * ARK_S_MAX * sizeof(realtype)); | ||
833 | realtype *ae = (realtype *)malloc(ARK_S_MAX * ARK_S_MAX * sizeof(realtype)); | ||
834 | realtype *ci = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
835 | realtype *ce = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
836 | realtype *bi = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
837 | realtype *be = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
838 | realtype *b2i = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
839 | realtype *b2e = (realtype *)malloc(ARK_S_MAX * sizeof(realtype)); | ||
840 | flag = ARKodeGetCurrentButcherTables(arkode_mem, &s, &q, &p, ai, ae, ci, ce, bi, be, b2i, b2e); | ||
841 | if (check_flag(&flag, "ARKode", 1)) return 1; | ||
842 | $vec-ptr:(int *btSQPMut)[0] = s; | ||
843 | $vec-ptr:(int *btSQPMut)[1] = q; | ||
844 | $vec-ptr:(int *btSQPMut)[2] = p; | ||
845 | for (i = 0; i < s; i++) { | ||
846 | for (j = 0; j < s; j++) { | ||
847 | /* FIXME: double should be realtype */ | ||
848 | ($vec-ptr:(double *btAsMut))[i * ARK_S_MAX + j] = ai[i * ARK_S_MAX + j]; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | for (i = 0; i < s; i++) { | ||
853 | ($vec-ptr:(double *btCsMut))[i] = ci[i]; | ||
854 | ($vec-ptr:(double *btBsMut))[i] = bi[i]; | ||
855 | ($vec-ptr:(double *btB2sMut))[i] = b2i[i]; | ||
856 | } | ||
857 | |||
858 | /* Clean up and return */ | ||
859 | N_VDestroy(y); /* Free y vector */ | ||
860 | ARKodeFree(&arkode_mem); /* Free integrator memory */ | ||
861 | |||
862 | return flag; | ||
863 | } |] | ||
864 | if res == 0 | ||
865 | then do | ||
866 | x <- V.freeze btAsMut | ||
867 | y <- V.freeze btSQPMut | ||
868 | z <- V.freeze btCsMut | ||
869 | u <- V.freeze btBsMut | ||
870 | v <- V.freeze btB2sMut | ||
871 | return $ Right (ButcherTable' { am' = x, cv' = z, bv' = u, b2v' = v }, y) | ||
872 | else do | ||
873 | return $ Left res | ||
874 | |||
875 | -- | Adaptive step-size control | ||
876 | -- functions. | ||
877 | -- | ||
878 | -- [GSL](https://www.gnu.org/software/gsl/doc/html/ode-initval.html#adaptive-step-size-control) | ||
879 | -- allows the user to control the step size adjustment using | ||
880 | -- \(D_i = \epsilon^{abs}s_i + \epsilon^{rel}(a_{y} |y_i| + a_{dy/dt} h |\dot{y}_i|)\) where | ||
881 | -- \(\epsilon^{abs}\) is the required absolute error, \(\epsilon^{rel}\) | ||
882 | -- is the required relative error, \(s_i\) is a vector of scaling | ||
883 | -- factors, \(a_{y}\) is a scaling factor for the solution \(y\) and | ||
884 | -- \(a_{dydt}\) is a scaling factor for the derivative of the solution \(dy/dt\). | ||
885 | -- | ||
886 | -- [ARKode](https://computation.llnl.gov/projects/sundials/arkode) | ||
887 | -- allows the user to control the step size adjustment using | ||
888 | -- \(\eta^{rel}|y_i| + \eta^{abs}_i\). For compatibility with | ||
889 | -- [hmatrix-gsl](https://hackage.haskell.org/package/hmatrix-gsl), | ||
890 | -- tolerances for \(y\) and \(\dot{y}\) can be specified but the latter have no | ||
891 | -- effect. | ||
892 | data StepControl = X Double Double -- ^ absolute and relative tolerance for \(y\); in GSL terms, \(a_{y} = 1\) and \(a_{dy/dt} = 0\); in ARKode terms, the \(\eta^{abs}_i\) are identical | ||
893 | | X' Double Double -- ^ absolute and relative tolerance for \(\dot{y}\); in GSL terms, \(a_{y} = 0\) and \(a_{dy/dt} = 1\); in ARKode terms, the latter is treated as the relative tolerance for \(y\) so this is the same as specifying 'X' which may be entirely incorrect for the given problem | ||
894 | | XX' Double Double Double Double -- ^ include both via relative tolerance | ||
895 | -- scaling factors \(a_y\), \(a_{{dy}/{dt}}\); in ARKode terms, the latter is ignored and \(\eta^{rel} = a_{y}\epsilon^{rel}\) | ||
896 | | ScXX' Double Double Double Double (Vector Double) -- ^ scale absolute tolerance of \(y_i\); in ARKode terms, \(a_{{dy}/{dt}}\) is ignored, \(\eta^{abs}_i = s_i \epsilon^{abs}\) and \(\eta^{rel} = a_{y}\epsilon^{rel}\) | ||
diff --git a/packages/sundials/src/Numeric/Sundials/Arkode.hsc b/packages/sundials/src/Numeric/Sundials/Arkode.hsc deleted file mode 100644 index 0850258..0000000 --- a/packages/sundials/src/Numeric/Sundials/Arkode.hsc +++ /dev/null | |||
@@ -1,204 +0,0 @@ | |||
1 | {-# LANGUAGE QuasiQuotes #-} | ||
2 | {-# LANGUAGE TemplateHaskell #-} | ||
3 | {-# LANGUAGE OverloadedStrings #-} | ||
4 | {-# LANGUAGE EmptyDataDecls #-} | ||
5 | |||
6 | module Numeric.Sundials.Arkode where | ||
7 | |||
8 | import Foreign | ||
9 | import Foreign.C.Types | ||
10 | |||
11 | import Language.C.Types as CT | ||
12 | |||
13 | import qualified Data.Vector.Storable as VS | ||
14 | import qualified Data.Vector.Storable.Mutable as VM | ||
15 | |||
16 | import qualified Language.Haskell.TH as TH | ||
17 | import qualified Data.Map as Map | ||
18 | import Language.C.Inline.Context | ||
19 | |||
20 | import qualified Data.Vector.Storable as V | ||
21 | |||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <sundials/sundials_nvector.h> | ||
25 | #include <sundials/sundials_matrix.h> | ||
26 | #include <nvector/nvector_serial.h> | ||
27 | #include <sunmatrix/sunmatrix_dense.h> | ||
28 | #include <arkode/arkode.h> | ||
29 | #include <cvode/cvode.h> | ||
30 | |||
31 | |||
32 | data SunVector | ||
33 | data SunMatrix = SunMatrix { rows :: CInt | ||
34 | , cols :: CInt | ||
35 | , vals :: V.Vector CDouble | ||
36 | } | ||
37 | |||
38 | -- | This is true only if configured/ built as 64 bits | ||
39 | type SunIndexType = CLong | ||
40 | |||
41 | sunTypesTable :: Map.Map TypeSpecifier TH.TypeQ | ||
42 | sunTypesTable = Map.fromList | ||
43 | [ | ||
44 | (TypeName "sunindextype", [t| SunIndexType |] ) | ||
45 | , (TypeName "SunVector", [t| SunVector |] ) | ||
46 | , (TypeName "SunMatrix", [t| SunMatrix |] ) | ||
47 | ] | ||
48 | |||
49 | sunCtx :: Context | ||
50 | sunCtx = mempty {ctxTypesTable = sunTypesTable} | ||
51 | |||
52 | getMatrixDataFromContents :: Ptr SunMatrix -> IO SunMatrix | ||
53 | getMatrixDataFromContents ptr = do | ||
54 | qtr <- getContentMatrixPtr ptr | ||
55 | rs <- getNRows qtr | ||
56 | cs <- getNCols qtr | ||
57 | rtr <- getMatrixData qtr | ||
58 | vs <- vectorFromC (fromIntegral $ rs * cs) rtr | ||
59 | return $ SunMatrix { rows = rs, cols = cs, vals = vs } | ||
60 | |||
61 | putMatrixDataFromContents :: SunMatrix -> Ptr SunMatrix -> IO () | ||
62 | putMatrixDataFromContents mat ptr = do | ||
63 | let rs = rows mat | ||
64 | cs = cols mat | ||
65 | vs = vals mat | ||
66 | qtr <- getContentMatrixPtr ptr | ||
67 | putNRows rs qtr | ||
68 | putNCols cs qtr | ||
69 | rtr <- getMatrixData qtr | ||
70 | vectorToC vs (fromIntegral $ rs * cs) rtr | ||
71 | |||
72 | instance Storable SunMatrix where | ||
73 | poke = flip putMatrixDataFromContents | ||
74 | peek = getMatrixDataFromContents | ||
75 | sizeOf _ = error "sizeOf not supported for SunMatrix" | ||
76 | alignment _ = error "alignment not supported for SunMatrix" | ||
77 | |||
78 | vectorFromC :: Storable a => Int -> Ptr a -> IO (VS.Vector a) | ||
79 | vectorFromC len ptr = do | ||
80 | ptr' <- newForeignPtr_ ptr | ||
81 | VS.freeze $ VM.unsafeFromForeignPtr0 ptr' len | ||
82 | |||
83 | vectorToC :: Storable a => VS.Vector a -> Int -> Ptr a -> IO () | ||
84 | vectorToC vec len ptr = do | ||
85 | ptr' <- newForeignPtr_ ptr | ||
86 | VS.copy (VM.unsafeFromForeignPtr0 ptr' len) vec | ||
87 | |||
88 | getDataFromContents :: Int -> Ptr SunVector -> IO (VS.Vector CDouble) | ||
89 | getDataFromContents len ptr = do | ||
90 | qtr <- getContentPtr ptr | ||
91 | rtr <- getData qtr | ||
92 | vectorFromC len rtr | ||
93 | |||
94 | putDataInContents :: Storable a => VS.Vector a -> Int -> Ptr b -> IO () | ||
95 | putDataInContents vec len ptr = do | ||
96 | qtr <- getContentPtr ptr | ||
97 | rtr <- getData qtr | ||
98 | vectorToC vec len rtr | ||
99 | |||
100 | #def typedef struct _generic_N_Vector SunVector; | ||
101 | #def typedef struct _N_VectorContent_Serial SunContent; | ||
102 | |||
103 | #def typedef struct _generic_SUNMatrix SunMatrix; | ||
104 | #def typedef struct _SUNMatrixContent_Dense SunMatrixContent; | ||
105 | |||
106 | getContentMatrixPtr :: Storable a => Ptr b -> IO a | ||
107 | getContentMatrixPtr ptr = (#peek SunMatrix, content) ptr | ||
108 | |||
109 | getNRows :: Ptr b -> IO CInt | ||
110 | getNRows ptr = (#peek SunMatrixContent, M) ptr | ||
111 | putNRows :: CInt -> Ptr b -> IO () | ||
112 | putNRows nr ptr = (#poke SunMatrixContent, M) ptr nr | ||
113 | |||
114 | getNCols :: Ptr b -> IO CInt | ||
115 | getNCols ptr = (#peek SunMatrixContent, N) ptr | ||
116 | putNCols :: CInt -> Ptr b -> IO () | ||
117 | putNCols nc ptr = (#poke SunMatrixContent, N) ptr nc | ||
118 | |||
119 | getMatrixData :: Storable a => Ptr b -> IO a | ||
120 | getMatrixData ptr = (#peek SunMatrixContent, data) ptr | ||
121 | |||
122 | getContentPtr :: Storable a => Ptr b -> IO a | ||
123 | getContentPtr ptr = (#peek SunVector, content) ptr | ||
124 | |||
125 | getData :: Storable a => Ptr b -> IO a | ||
126 | getData ptr = (#peek SunContent, data) ptr | ||
127 | |||
128 | cV_ADAMS :: Int | ||
129 | cV_ADAMS = #const CV_ADAMS | ||
130 | cV_BDF :: Int | ||
131 | cV_BDF = #const CV_BDF | ||
132 | |||
133 | arkSMax :: Int | ||
134 | arkSMax = #const ARK_S_MAX | ||
135 | |||
136 | mIN_DIRK_NUM, mAX_DIRK_NUM :: Int | ||
137 | mIN_DIRK_NUM = #const MIN_DIRK_NUM | ||
138 | mAX_DIRK_NUM = #const MAX_DIRK_NUM | ||
139 | |||
140 | -- FIXME: We could just use inline-c instead | ||
141 | |||
142 | -- Butcher table accessors -- implicit | ||
143 | sDIRK_2_1_2 :: Int | ||
144 | sDIRK_2_1_2 = #const SDIRK_2_1_2 | ||
145 | bILLINGTON_3_3_2 :: Int | ||
146 | bILLINGTON_3_3_2 = #const BILLINGTON_3_3_2 | ||
147 | tRBDF2_3_3_2 :: Int | ||
148 | tRBDF2_3_3_2 = #const TRBDF2_3_3_2 | ||
149 | kVAERNO_4_2_3 :: Int | ||
150 | kVAERNO_4_2_3 = #const KVAERNO_4_2_3 | ||
151 | aRK324L2SA_DIRK_4_2_3 :: Int | ||
152 | aRK324L2SA_DIRK_4_2_3 = #const ARK324L2SA_DIRK_4_2_3 | ||
153 | cASH_5_2_4 :: Int | ||
154 | cASH_5_2_4 = #const CASH_5_2_4 | ||
155 | cASH_5_3_4 :: Int | ||
156 | cASH_5_3_4 = #const CASH_5_3_4 | ||
157 | sDIRK_5_3_4 :: Int | ||
158 | sDIRK_5_3_4 = #const SDIRK_5_3_4 | ||
159 | kVAERNO_5_3_4 :: Int | ||
160 | kVAERNO_5_3_4 = #const KVAERNO_5_3_4 | ||
161 | aRK436L2SA_DIRK_6_3_4 :: Int | ||
162 | aRK436L2SA_DIRK_6_3_4 = #const ARK436L2SA_DIRK_6_3_4 | ||
163 | kVAERNO_7_4_5 :: Int | ||
164 | kVAERNO_7_4_5 = #const KVAERNO_7_4_5 | ||
165 | aRK548L2SA_DIRK_8_4_5 :: Int | ||
166 | aRK548L2SA_DIRK_8_4_5 = #const ARK548L2SA_DIRK_8_4_5 | ||
167 | |||
168 | -- #define DEFAULT_DIRK_2 SDIRK_2_1_2 | ||
169 | -- #define DEFAULT_DIRK_3 ARK324L2SA_DIRK_4_2_3 | ||
170 | -- #define DEFAULT_DIRK_4 SDIRK_5_3_4 | ||
171 | -- #define DEFAULT_DIRK_5 ARK548L2SA_DIRK_8_4_5 | ||
172 | |||
173 | -- Butcher table accessors -- explicit | ||
174 | hEUN_EULER_2_1_2 :: Int | ||
175 | hEUN_EULER_2_1_2 = #const HEUN_EULER_2_1_2 | ||
176 | bOGACKI_SHAMPINE_4_2_3 :: Int | ||
177 | bOGACKI_SHAMPINE_4_2_3 = #const BOGACKI_SHAMPINE_4_2_3 | ||
178 | aRK324L2SA_ERK_4_2_3 :: Int | ||
179 | aRK324L2SA_ERK_4_2_3 = #const ARK324L2SA_ERK_4_2_3 | ||
180 | zONNEVELD_5_3_4 :: Int | ||
181 | zONNEVELD_5_3_4 = #const ZONNEVELD_5_3_4 | ||
182 | aRK436L2SA_ERK_6_3_4 :: Int | ||
183 | aRK436L2SA_ERK_6_3_4 = #const ARK436L2SA_ERK_6_3_4 | ||
184 | sAYFY_ABURUB_6_3_4 :: Int | ||
185 | sAYFY_ABURUB_6_3_4 = #const SAYFY_ABURUB_6_3_4 | ||
186 | cASH_KARP_6_4_5 :: Int | ||
187 | cASH_KARP_6_4_5 = #const CASH_KARP_6_4_5 | ||
188 | fEHLBERG_6_4_5 :: Int | ||
189 | fEHLBERG_6_4_5 = #const FEHLBERG_6_4_5 | ||
190 | dORMAND_PRINCE_7_4_5 :: Int | ||
191 | dORMAND_PRINCE_7_4_5 = #const DORMAND_PRINCE_7_4_5 | ||
192 | aRK548L2SA_ERK_8_4_5 :: Int | ||
193 | aRK548L2SA_ERK_8_4_5 = #const ARK548L2SA_ERK_8_4_5 | ||
194 | vERNER_8_5_6 :: Int | ||
195 | vERNER_8_5_6 = #const VERNER_8_5_6 | ||
196 | fEHLBERG_13_7_8 :: Int | ||
197 | fEHLBERG_13_7_8 = #const FEHLBERG_13_7_8 | ||
198 | |||
199 | -- #define DEFAULT_ERK_2 HEUN_EULER_2_1_2 | ||
200 | -- #define DEFAULT_ERK_3 BOGACKI_SHAMPINE_4_2_3 | ||
201 | -- #define DEFAULT_ERK_4 ZONNEVELD_5_3_4 | ||
202 | -- #define DEFAULT_ERK_5 CASH_KARP_6_4_5 | ||
203 | -- #define DEFAULT_ERK_6 VERNER_8_5_6 | ||
204 | -- #define DEFAULT_ERK_8 FEHLBERG_13_7_8 | ||
diff --git a/packages/sundials/src/Numeric/Sundials/CVode/ODE.hs b/packages/sundials/src/Numeric/Sundials/CVode/ODE.hs deleted file mode 100644 index ad7cf51..0000000 --- a/packages/sundials/src/Numeric/Sundials/CVode/ODE.hs +++ /dev/null | |||
@@ -1,471 +0,0 @@ | |||
1 | {-# OPTIONS_GHC -Wall #-} | ||
2 | |||
3 | {-# LANGUAGE QuasiQuotes #-} | ||
4 | {-# LANGUAGE TemplateHaskell #-} | ||
5 | {-# LANGUAGE MultiWayIf #-} | ||
6 | {-# LANGUAGE OverloadedStrings #-} | ||
7 | {-# LANGUAGE ScopedTypeVariables #-} | ||
8 | |||
9 | ----------------------------------------------------------------------------- | ||
10 | -- | | ||
11 | -- Module : Numeric.Sundials.CVode.ODE | ||
12 | -- Copyright : Dominic Steinitz 2018, | ||
13 | -- Novadiscovery 2018 | ||
14 | -- License : BSD | ||
15 | -- Maintainer : Dominic Steinitz | ||
16 | -- Stability : provisional | ||
17 | -- | ||
18 | -- Solution of ordinary differential equation (ODE) initial value problems. | ||
19 | -- | ||
20 | -- <https://computation.llnl.gov/projects/sundials/sundials-software> | ||
21 | -- | ||
22 | -- A simple example: | ||
23 | -- | ||
24 | -- <<diagrams/brusselator.png#diagram=brusselator&height=400&width=500>> | ||
25 | -- | ||
26 | -- @ | ||
27 | -- import Numeric.Sundials.CVode.ODE | ||
28 | -- import Numeric.LinearAlgebra | ||
29 | -- | ||
30 | -- import Plots as P | ||
31 | -- import qualified Diagrams.Prelude as D | ||
32 | -- import Diagrams.Backend.Rasterific | ||
33 | -- | ||
34 | -- brusselator :: Double -> [Double] -> [Double] | ||
35 | -- brusselator _t x = [ a - (w + 1) * u + v * u * u | ||
36 | -- , w * u - v * u * u | ||
37 | -- , (b - w) / eps - w * u | ||
38 | -- ] | ||
39 | -- where | ||
40 | -- a = 1.0 | ||
41 | -- b = 3.5 | ||
42 | -- eps = 5.0e-6 | ||
43 | -- u = x !! 0 | ||
44 | -- v = x !! 1 | ||
45 | -- w = x !! 2 | ||
46 | -- | ||
47 | -- lSaxis :: [[Double]] -> P.Axis B D.V2 Double | ||
48 | -- lSaxis xs = P.r2Axis &~ do | ||
49 | -- let ts = xs!!0 | ||
50 | -- us = xs!!1 | ||
51 | -- vs = xs!!2 | ||
52 | -- ws = xs!!3 | ||
53 | -- P.linePlot' $ zip ts us | ||
54 | -- P.linePlot' $ zip ts vs | ||
55 | -- P.linePlot' $ zip ts ws | ||
56 | -- | ||
57 | -- main = do | ||
58 | -- let res1 = odeSolve brusselator [1.2, 3.1, 3.0] (fromList [0.0, 0.1 .. 10.0]) | ||
59 | -- renderRasterific "diagrams/brusselator.png" | ||
60 | -- (D.dims2D 500.0 500.0) | ||
61 | -- (renderAxis $ lSaxis $ [0.0, 0.1 .. 10.0]:(toLists $ tr res1)) | ||
62 | -- @ | ||
63 | -- | ||
64 | ----------------------------------------------------------------------------- | ||
65 | module Numeric.Sundials.CVode.ODE ( odeSolve | ||
66 | , odeSolveV | ||
67 | , odeSolveVWith | ||
68 | , odeSolveVWith' | ||
69 | , ODEMethod(..) | ||
70 | , StepControl(..) | ||
71 | ) where | ||
72 | |||
73 | import qualified Language.C.Inline as C | ||
74 | import qualified Language.C.Inline.Unsafe as CU | ||
75 | |||
76 | import Data.Monoid ((<>)) | ||
77 | import Data.Maybe (isJust) | ||
78 | |||
79 | import Foreign.C.Types (CDouble, CInt, CLong) | ||
80 | import Foreign.Ptr (Ptr) | ||
81 | import Foreign.Storable (poke) | ||
82 | |||
83 | import qualified Data.Vector.Storable as V | ||
84 | |||
85 | import Data.Coerce (coerce) | ||
86 | import System.IO.Unsafe (unsafePerformIO) | ||
87 | |||
88 | import Numeric.LinearAlgebra.Devel (createVector) | ||
89 | |||
90 | import Numeric.LinearAlgebra.HMatrix (Vector, Matrix, toList, rows, | ||
91 | cols, toLists, size, reshape) | ||
92 | |||
93 | import Numeric.Sundials.Arkode (cV_ADAMS, cV_BDF, | ||
94 | getDataFromContents, putDataInContents) | ||
95 | import qualified Numeric.Sundials.Arkode as T | ||
96 | import Numeric.Sundials.ODEOpts (ODEOpts(..), Jacobian, SundialsDiagnostics(..)) | ||
97 | |||
98 | |||
99 | C.context (C.baseCtx <> C.vecCtx <> C.funCtx <> T.sunCtx) | ||
100 | |||
101 | C.include "<stdlib.h>" | ||
102 | C.include "<stdio.h>" | ||
103 | C.include "<math.h>" | ||
104 | C.include "<cvode/cvode.h>" -- prototypes for CVODE fcts., consts. | ||
105 | C.include "<nvector/nvector_serial.h>" -- serial N_Vector types, fcts., macros | ||
106 | C.include "<sunmatrix/sunmatrix_dense.h>" -- access to dense SUNMatrix | ||
107 | C.include "<sunlinsol/sunlinsol_dense.h>" -- access to dense SUNLinearSolver | ||
108 | C.include "<cvode/cvode_direct.h>" -- access to CVDls interface | ||
109 | C.include "<sundials/sundials_types.h>" -- definition of type realtype | ||
110 | C.include "<sundials/sundials_math.h>" | ||
111 | C.include "../../../helpers.h" | ||
112 | C.include "Numeric/Sundials/Arkode_hsc.h" | ||
113 | |||
114 | |||
115 | -- | Stepping functions | ||
116 | data ODEMethod = ADAMS | ||
117 | | BDF | ||
118 | |||
119 | getMethod :: ODEMethod -> Int | ||
120 | getMethod (ADAMS) = cV_ADAMS | ||
121 | getMethod (BDF) = cV_BDF | ||
122 | |||
123 | getJacobian :: ODEMethod -> Maybe Jacobian | ||
124 | getJacobian _ = Nothing | ||
125 | |||
126 | -- | A version of 'odeSolveVWith' with reasonable default step control. | ||
127 | odeSolveV | ||
128 | :: ODEMethod | ||
129 | -> Maybe Double -- ^ initial step size - by default, CVode | ||
130 | -- estimates the initial step size to be the | ||
131 | -- solution \(h\) of the equation | ||
132 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
133 | -- \(\ddot{y}\) is an estimated value of the | ||
134 | -- second derivative of the solution at \(t_0\) | ||
135 | -> Double -- ^ absolute tolerance for the state vector | ||
136 | -> Double -- ^ relative tolerance for the state vector | ||
137 | -> (Double -> Vector Double -> Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
138 | -> Vector Double -- ^ initial conditions | ||
139 | -> Vector Double -- ^ desired solution times | ||
140 | -> Matrix Double -- ^ solution | ||
141 | odeSolveV meth hi epsAbs epsRel f y0 ts = | ||
142 | odeSolveVWith meth (X epsAbs epsRel) hi g y0 ts | ||
143 | where | ||
144 | g t x0 = coerce $ f t x0 | ||
145 | |||
146 | -- | A version of 'odeSolveV' with reasonable default parameters and | ||
147 | -- system of equations defined using lists. FIXME: we should say | ||
148 | -- something about the fact we could use the Jacobian but don't for | ||
149 | -- compatibility with hmatrix-gsl. | ||
150 | odeSolve :: (Double -> [Double] -> [Double]) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
151 | -> [Double] -- ^ initial conditions | ||
152 | -> Vector Double -- ^ desired solution times | ||
153 | -> Matrix Double -- ^ solution | ||
154 | odeSolve f y0 ts = | ||
155 | -- FIXME: These tolerances are different from the ones in GSL | ||
156 | odeSolveVWith BDF (XX' 1.0e-6 1.0e-10 1 1) Nothing g (V.fromList y0) (V.fromList $ toList ts) | ||
157 | where | ||
158 | g t x0 = V.fromList $ f t (V.toList x0) | ||
159 | |||
160 | odeSolveVWith :: | ||
161 | ODEMethod | ||
162 | -> StepControl | ||
163 | -> Maybe Double -- ^ initial step size - by default, CVode | ||
164 | -- estimates the initial step size to be the | ||
165 | -- solution \(h\) of the equation | ||
166 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
167 | -- \(\ddot{y}\) is an estimated value of the second | ||
168 | -- derivative of the solution at \(t_0\) | ||
169 | -> (Double -> V.Vector Double -> V.Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
170 | -> V.Vector Double -- ^ Initial conditions | ||
171 | -> V.Vector Double -- ^ Desired solution times | ||
172 | -> Matrix Double -- ^ Error code or solution | ||
173 | odeSolveVWith method control initStepSize f y0 tt = | ||
174 | case odeSolveVWith' opts method control initStepSize f y0 tt of | ||
175 | Left (c, _v) -> error $ show c -- FIXME | ||
176 | Right (v, _d) -> v | ||
177 | where | ||
178 | opts = ODEOpts { maxNumSteps = 10000 | ||
179 | , minStep = 1.0e-12 | ||
180 | , relTol = error "relTol" | ||
181 | , absTols = error "absTol" | ||
182 | , initStep = error "initStep" | ||
183 | , maxFail = 10 | ||
184 | } | ||
185 | |||
186 | odeSolveVWith' :: | ||
187 | ODEOpts | ||
188 | -> ODEMethod | ||
189 | -> StepControl | ||
190 | -> Maybe Double -- ^ initial step size - by default, CVode | ||
191 | -- estimates the initial step size to be the | ||
192 | -- solution \(h\) of the equation | ||
193 | -- \(\|\frac{h^2\ddot{y}}{2}\| = 1\), where | ||
194 | -- \(\ddot{y}\) is an estimated value of the second | ||
195 | -- derivative of the solution at \(t_0\) | ||
196 | -> (Double -> V.Vector Double -> V.Vector Double) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
197 | -> V.Vector Double -- ^ Initial conditions | ||
198 | -> V.Vector Double -- ^ Desired solution times | ||
199 | -> Either (Matrix Double, Int) (Matrix Double, SundialsDiagnostics) -- ^ Error code or solution | ||
200 | odeSolveVWith' opts method control initStepSize f y0 tt = | ||
201 | case solveOdeC (fromIntegral $ maxFail opts) | ||
202 | (fromIntegral $ maxNumSteps opts) (coerce $ minStep opts) | ||
203 | (fromIntegral $ getMethod method) (coerce initStepSize) jacH (scise control) | ||
204 | (coerce f) (coerce y0) (coerce tt) of | ||
205 | Left (v, c) -> Left (reshape l (coerce v), fromIntegral c) | ||
206 | Right (v, d) -> Right (reshape l (coerce v), d) | ||
207 | where | ||
208 | l = size y0 | ||
209 | scise (X aTol rTol) = coerce (V.replicate l aTol, rTol) | ||
210 | scise (X' aTol rTol) = coerce (V.replicate l aTol, rTol) | ||
211 | scise (XX' aTol rTol yScale _yDotScale) = coerce (V.replicate l aTol, yScale * rTol) | ||
212 | -- FIXME; Should we check that the length of ss is correct? | ||
213 | scise (ScXX' aTol rTol yScale _yDotScale ss) = coerce (V.map (* aTol) ss, yScale * rTol) | ||
214 | jacH = fmap (\g t v -> matrixToSunMatrix $ g (coerce t) (coerce v)) $ | ||
215 | getJacobian method | ||
216 | matrixToSunMatrix m = T.SunMatrix { T.rows = nr, T.cols = nc, T.vals = vs } | ||
217 | where | ||
218 | nr = fromIntegral $ rows m | ||
219 | nc = fromIntegral $ cols m | ||
220 | -- FIXME: efficiency | ||
221 | vs = V.fromList $ map coerce $ concat $ toLists m | ||
222 | |||
223 | solveOdeC :: | ||
224 | CInt -> | ||
225 | CLong -> | ||
226 | CDouble -> | ||
227 | CInt -> | ||
228 | Maybe CDouble -> | ||
229 | (Maybe (CDouble -> V.Vector CDouble -> T.SunMatrix)) -> | ||
230 | (V.Vector CDouble, CDouble) -> | ||
231 | (CDouble -> V.Vector CDouble -> V.Vector CDouble) -- ^ The RHS of the system \(\dot{y} = f(t,y)\) | ||
232 | -> V.Vector CDouble -- ^ Initial conditions | ||
233 | -> V.Vector CDouble -- ^ Desired solution times | ||
234 | -> Either (V.Vector CDouble, CInt) (V.Vector CDouble, SundialsDiagnostics) -- ^ Partial solution and error code or | ||
235 | -- solution and diagnostics | ||
236 | solveOdeC maxErrTestFails maxNumSteps_ minStep_ method initStepSize | ||
237 | jacH (aTols, rTol) fun f0 ts = | ||
238 | unsafePerformIO $ do | ||
239 | |||
240 | let isInitStepSize :: CInt | ||
241 | isInitStepSize = fromIntegral $ fromEnum $ isJust initStepSize | ||
242 | ss :: CDouble | ||
243 | ss = case initStepSize of | ||
244 | -- It would be better to put an error message here but | ||
245 | -- inline-c seems to evaluate this even if it is never | ||
246 | -- used :( | ||
247 | Nothing -> 0.0 | ||
248 | Just x -> x | ||
249 | |||
250 | let dim = V.length f0 | ||
251 | nEq :: CLong | ||
252 | nEq = fromIntegral dim | ||
253 | nTs :: CInt | ||
254 | nTs = fromIntegral $ V.length ts | ||
255 | quasiMatrixRes <- createVector ((fromIntegral dim) * (fromIntegral nTs)) | ||
256 | qMatMut <- V.thaw quasiMatrixRes | ||
257 | diagnostics :: V.Vector CLong <- createVector 10 -- FIXME | ||
258 | diagMut <- V.thaw diagnostics | ||
259 | -- We need the types that sundials expects. These are tied together | ||
260 | -- in 'CLangToHaskellTypes'. FIXME: The Haskell type is currently empty! | ||
261 | let funIO :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr () -> IO CInt | ||
262 | funIO x y f _ptr = do | ||
263 | -- Convert the pointer we get from C (y) to a vector, and then | ||
264 | -- apply the user-supplied function. | ||
265 | fImm <- fun x <$> getDataFromContents dim y | ||
266 | -- Fill in the provided pointer with the resulting vector. | ||
267 | putDataInContents fImm dim f | ||
268 | -- FIXME: I don't understand what this comment means | ||
269 | -- Unsafe since the function will be called many times. | ||
270 | [CU.exp| int{ 0 } |] | ||
271 | let isJac :: CInt | ||
272 | isJac = fromIntegral $ fromEnum $ isJust jacH | ||
273 | jacIO :: CDouble -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr T.SunMatrix -> | ||
274 | Ptr () -> Ptr T.SunVector -> Ptr T.SunVector -> Ptr T.SunVector -> | ||
275 | IO CInt | ||
276 | jacIO t y _fy jacS _ptr _tmp1 _tmp2 _tmp3 = do | ||
277 | case jacH of | ||
278 | Nothing -> error "Numeric.Sundials.CVode.ODE: Jacobian not defined" | ||
279 | Just jacI -> do j <- jacI t <$> getDataFromContents dim y | ||
280 | poke jacS j | ||
281 | -- FIXME: I don't understand what this comment means | ||
282 | -- Unsafe since the function will be called many times. | ||
283 | [CU.exp| int{ 0 } |] | ||
284 | |||
285 | res <- [C.block| int { | ||
286 | /* general problem variables */ | ||
287 | |||
288 | int flag; /* reusable error-checking flag */ | ||
289 | int i, j; /* reusable loop indices */ | ||
290 | N_Vector y = NULL; /* empty vector for storing solution */ | ||
291 | N_Vector tv = NULL; /* empty vector for storing absolute tolerances */ | ||
292 | |||
293 | SUNMatrix A = NULL; /* empty matrix for linear solver */ | ||
294 | SUNLinearSolver LS = NULL; /* empty linear solver object */ | ||
295 | void *cvode_mem = NULL; /* empty CVODE memory structure */ | ||
296 | realtype t; | ||
297 | long int nst, nfe, nsetups, nje, nfeLS, nni, ncfn, netf, nge; | ||
298 | |||
299 | /* general problem parameters */ | ||
300 | |||
301 | realtype T0 = RCONST(($vec-ptr:(double *ts))[0]); /* initial time */ | ||
302 | sunindextype NEQ = $(sunindextype nEq); /* number of dependent vars. */ | ||
303 | |||
304 | /* Initialize data structures */ | ||
305 | |||
306 | y = N_VNew_Serial(NEQ); /* Create serial vector for solution */ | ||
307 | if (check_flag((void *)y, "N_VNew_Serial", 0)) return 1; | ||
308 | /* Specify initial condition */ | ||
309 | for (i = 0; i < NEQ; i++) { | ||
310 | NV_Ith_S(y,i) = ($vec-ptr:(double *f0))[i]; | ||
311 | }; | ||
312 | |||
313 | cvode_mem = CVodeCreate($(int method), CV_NEWTON); | ||
314 | if (check_flag((void *)cvode_mem, "CVodeCreate", 0)) return(1); | ||
315 | |||
316 | /* Call CVodeInit to initialize the integrator memory and specify the | ||
317 | * user's right hand side function in y'=f(t,y), the inital time T0, and | ||
318 | * the initial dependent variable vector y. */ | ||
319 | flag = CVodeInit(cvode_mem, $fun:(int (* funIO) (double t, SunVector y[], SunVector dydt[], void * params)), T0, y); | ||
320 | if (check_flag(&flag, "CVodeInit", 1)) return(1); | ||
321 | |||
322 | tv = N_VNew_Serial(NEQ); /* Create serial vector for absolute tolerances */ | ||
323 | if (check_flag((void *)tv, "N_VNew_Serial", 0)) return 1; | ||
324 | /* Specify tolerances */ | ||
325 | for (i = 0; i < NEQ; i++) { | ||
326 | NV_Ith_S(tv,i) = ($vec-ptr:(double *aTols))[i]; | ||
327 | }; | ||
328 | |||
329 | flag = CVodeSetMinStep(cvode_mem, $(double minStep_)); | ||
330 | if (check_flag(&flag, "CVodeSetMinStep", 1)) return 1; | ||
331 | flag = CVodeSetMaxNumSteps(cvode_mem, $(long int maxNumSteps_)); | ||
332 | if (check_flag(&flag, "CVodeSetMaxNumSteps", 1)) return 1; | ||
333 | flag = CVodeSetMaxErrTestFails(cvode_mem, $(int maxErrTestFails)); | ||
334 | if (check_flag(&flag, "CVodeSetMaxErrTestFails", 1)) return 1; | ||
335 | |||
336 | /* Call CVodeSVtolerances to specify the scalar relative tolerance | ||
337 | * and vector absolute tolerances */ | ||
338 | flag = CVodeSVtolerances(cvode_mem, $(double rTol), tv); | ||
339 | if (check_flag(&flag, "CVodeSVtolerances", 1)) return(1); | ||
340 | |||
341 | /* Initialize dense matrix data structure and solver */ | ||
342 | A = SUNDenseMatrix(NEQ, NEQ); | ||
343 | if (check_flag((void *)A, "SUNDenseMatrix", 0)) return 1; | ||
344 | LS = SUNDenseLinearSolver(y, A); | ||
345 | if (check_flag((void *)LS, "SUNDenseLinearSolver", 0)) return 1; | ||
346 | |||
347 | /* Attach matrix and linear solver */ | ||
348 | flag = CVDlsSetLinearSolver(cvode_mem, LS, A); | ||
349 | if (check_flag(&flag, "CVDlsSetLinearSolver", 1)) return 1; | ||
350 | |||
351 | /* Set the initial step size if there is one */ | ||
352 | if ($(int isInitStepSize)) { | ||
353 | /* FIXME: We could check if the initial step size is 0 */ | ||
354 | /* or even NaN and then throw an error */ | ||
355 | flag = CVodeSetInitStep(cvode_mem, $(double ss)); | ||
356 | if (check_flag(&flag, "CVodeSetInitStep", 1)) return 1; | ||
357 | } | ||
358 | |||
359 | /* Set the Jacobian if there is one */ | ||
360 | if ($(int isJac)) { | ||
361 | flag = CVDlsSetJacFn(cvode_mem, $fun:(int (* jacIO) (double t, SunVector y[], SunVector fy[], SunMatrix Jac[], void * params, SunVector tmp1[], SunVector tmp2[], SunVector tmp3[]))); | ||
362 | if (check_flag(&flag, "CVDlsSetJacFn", 1)) return 1; | ||
363 | } | ||
364 | |||
365 | /* Store initial conditions */ | ||
366 | for (j = 0; j < NEQ; j++) { | ||
367 | ($vec-ptr:(double *qMatMut))[0 * $(int nTs) + j] = NV_Ith_S(y,j); | ||
368 | } | ||
369 | |||
370 | /* Main time-stepping loop: calls CVode to perform the integration */ | ||
371 | /* Stops when the final time has been reached */ | ||
372 | for (i = 1; i < $(int nTs); i++) { | ||
373 | |||
374 | flag = CVode(cvode_mem, ($vec-ptr:(double *ts))[i], y, &t, CV_NORMAL); /* call integrator */ | ||
375 | if (check_flag(&flag, "CVode solver failure, stopping integration", 1)) return 1; | ||
376 | |||
377 | /* Store the results for Haskell */ | ||
378 | for (j = 0; j < NEQ; j++) { | ||
379 | ($vec-ptr:(double *qMatMut))[i * NEQ + j] = NV_Ith_S(y,j); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | /* Get some final statistics on how the solve progressed */ | ||
384 | |||
385 | flag = CVodeGetNumSteps(cvode_mem, &nst); | ||
386 | check_flag(&flag, "CVodeGetNumSteps", 1); | ||
387 | ($vec-ptr:(long int *diagMut))[0] = nst; | ||
388 | |||
389 | /* FIXME */ | ||
390 | ($vec-ptr:(long int *diagMut))[1] = 0; | ||
391 | |||
392 | flag = CVodeGetNumRhsEvals(cvode_mem, &nfe); | ||
393 | check_flag(&flag, "CVodeGetNumRhsEvals", 1); | ||
394 | ($vec-ptr:(long int *diagMut))[2] = nfe; | ||
395 | /* FIXME */ | ||
396 | ($vec-ptr:(long int *diagMut))[3] = 0; | ||
397 | |||
398 | flag = CVodeGetNumLinSolvSetups(cvode_mem, &nsetups); | ||
399 | check_flag(&flag, "CVodeGetNumLinSolvSetups", 1); | ||
400 | ($vec-ptr:(long int *diagMut))[4] = nsetups; | ||
401 | |||
402 | flag = CVodeGetNumErrTestFails(cvode_mem, &netf); | ||
403 | check_flag(&flag, "CVodeGetNumErrTestFails", 1); | ||
404 | ($vec-ptr:(long int *diagMut))[5] = netf; | ||
405 | |||
406 | flag = CVodeGetNumNonlinSolvIters(cvode_mem, &nni); | ||
407 | check_flag(&flag, "CVodeGetNumNonlinSolvIters", 1); | ||
408 | ($vec-ptr:(long int *diagMut))[6] = nni; | ||
409 | |||
410 | flag = CVodeGetNumNonlinSolvConvFails(cvode_mem, &ncfn); | ||
411 | check_flag(&flag, "CVodeGetNumNonlinSolvConvFails", 1); | ||
412 | ($vec-ptr:(long int *diagMut))[7] = ncfn; | ||
413 | |||
414 | flag = CVDlsGetNumJacEvals(cvode_mem, &nje); | ||
415 | check_flag(&flag, "CVDlsGetNumJacEvals", 1); | ||
416 | ($vec-ptr:(long int *diagMut))[8] = ncfn; | ||
417 | |||
418 | flag = CVDlsGetNumRhsEvals(cvode_mem, &nfeLS); | ||
419 | check_flag(&flag, "CVDlsGetNumRhsEvals", 1); | ||
420 | ($vec-ptr:(long int *diagMut))[9] = ncfn; | ||
421 | |||
422 | /* Clean up and return */ | ||
423 | |||
424 | N_VDestroy(y); /* Free y vector */ | ||
425 | N_VDestroy(tv); /* Free tv vector */ | ||
426 | CVodeFree(&cvode_mem); /* Free integrator memory */ | ||
427 | SUNLinSolFree(LS); /* Free linear solver */ | ||
428 | SUNMatDestroy(A); /* Free A matrix */ | ||
429 | |||
430 | return flag; | ||
431 | } |] | ||
432 | preD <- V.freeze diagMut | ||
433 | let d = SundialsDiagnostics (fromIntegral $ preD V.!0) | ||
434 | (fromIntegral $ preD V.!1) | ||
435 | (fromIntegral $ preD V.!2) | ||
436 | (fromIntegral $ preD V.!3) | ||
437 | (fromIntegral $ preD V.!4) | ||
438 | (fromIntegral $ preD V.!5) | ||
439 | (fromIntegral $ preD V.!6) | ||
440 | (fromIntegral $ preD V.!7) | ||
441 | (fromIntegral $ preD V.!8) | ||
442 | (fromIntegral $ preD V.!9) | ||
443 | m <- V.freeze qMatMut | ||
444 | if res == 0 | ||
445 | then do | ||
446 | return $ Right (m, d) | ||
447 | else do | ||
448 | return $ Left (m, res) | ||
449 | |||
450 | -- | Adaptive step-size control | ||
451 | -- functions. | ||
452 | -- | ||
453 | -- [GSL](https://www.gnu.org/software/gsl/doc/html/ode-initval.html#adaptive-step-size-control) | ||
454 | -- allows the user to control the step size adjustment using | ||
455 | -- \(D_i = \epsilon^{abs}s_i + \epsilon^{rel}(a_{y} |y_i| + a_{dy/dt} h |\dot{y}_i|)\) where | ||
456 | -- \(\epsilon^{abs}\) is the required absolute error, \(\epsilon^{rel}\) | ||
457 | -- is the required relative error, \(s_i\) is a vector of scaling | ||
458 | -- factors, \(a_{y}\) is a scaling factor for the solution \(y\) and | ||
459 | -- \(a_{dydt}\) is a scaling factor for the derivative of the solution \(dy/dt\). | ||
460 | -- | ||
461 | -- [ARKode](https://computation.llnl.gov/projects/sundials/arkode) | ||
462 | -- allows the user to control the step size adjustment using | ||
463 | -- \(\eta^{rel}|y_i| + \eta^{abs}_i\). For compatibility with | ||
464 | -- [hmatrix-gsl](https://hackage.haskell.org/package/hmatrix-gsl), | ||
465 | -- tolerances for \(y\) and \(\dot{y}\) can be specified but the latter have no | ||
466 | -- effect. | ||
467 | data StepControl = X Double Double -- ^ absolute and relative tolerance for \(y\); in GSL terms, \(a_{y} = 1\) and \(a_{dy/dt} = 0\); in ARKode terms, the \(\eta^{abs}_i\) are identical | ||
468 | | X' Double Double -- ^ absolute and relative tolerance for \(\dot{y}\); in GSL terms, \(a_{y} = 0\) and \(a_{dy/dt} = 1\); in ARKode terms, the latter is treated as the relative tolerance for \(y\) so this is the same as specifying 'X' which may be entirely incorrect for the given problem | ||
469 | | XX' Double Double Double Double -- ^ include both via relative tolerance | ||
470 | -- scaling factors \(a_y\), \(a_{{dy}/{dt}}\); in ARKode terms, the latter is ignored and \(\eta^{rel} = a_{y}\epsilon^{rel}\) | ||
471 | | ScXX' Double Double Double Double (Vector Double) -- ^ scale absolute tolerance of \(y_i\); in ARKode terms, \(a_{{dy}/{dt}}\) is ignored, \(\eta^{abs}_i = s_i \epsilon^{abs}\) and \(\eta^{rel} = a_{y}\epsilon^{rel}\) | ||
diff --git a/packages/sundials/src/Numeric/Sundials/ODEOpts.hs b/packages/sundials/src/Numeric/Sundials/ODEOpts.hs deleted file mode 100644 index 027d99a..0000000 --- a/packages/sundials/src/Numeric/Sundials/ODEOpts.hs +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | module Numeric.Sundials.ODEOpts where | ||
2 | |||
3 | import Data.Word (Word32) | ||
4 | import qualified Data.Vector.Storable as VS | ||
5 | |||
6 | import Numeric.LinearAlgebra.HMatrix (Vector, Matrix) | ||
7 | |||
8 | |||
9 | type Jacobian = Double -> Vector Double -> Matrix Double | ||
10 | |||
11 | data ODEOpts = ODEOpts { | ||
12 | maxNumSteps :: Word32 | ||
13 | , minStep :: Double | ||
14 | , relTol :: Double | ||
15 | , absTols :: VS.Vector Double | ||
16 | , initStep :: Maybe Double | ||
17 | , maxFail :: Word32 | ||
18 | } deriving (Read, Show, Eq, Ord) | ||
19 | |||
20 | data SundialsDiagnostics = SundialsDiagnostics { | ||
21 | aRKodeGetNumSteps :: Int | ||
22 | , aRKodeGetNumStepAttempts :: Int | ||
23 | , aRKodeGetNumRhsEvals_fe :: Int | ||
24 | , aRKodeGetNumRhsEvals_fi :: Int | ||
25 | , aRKodeGetNumLinSolvSetups :: Int | ||
26 | , aRKodeGetNumErrTestFails :: Int | ||
27 | , aRKodeGetNumNonlinSolvIters :: Int | ||
28 | , aRKodeGetNumNonlinSolvConvFails :: Int | ||
29 | , aRKDlsGetNumJacEvals :: Int | ||
30 | , aRKDlsGetNumRhsEvals :: Int | ||
31 | } deriving Show | ||
32 | |||
diff --git a/packages/sundials/src/helpers.c b/packages/sundials/src/helpers.c deleted file mode 100644 index f0ca592..0000000 --- a/packages/sundials/src/helpers.c +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <math.h> | ||
3 | #include <arkode/arkode.h> /* prototypes for ARKODE fcts., consts. */ | ||
4 | #include <nvector/nvector_serial.h> /* serial N_Vector types, fcts., macros */ | ||
5 | #include <sunmatrix/sunmatrix_dense.h> /* access to dense SUNMatrix */ | ||
6 | #include <sunlinsol/sunlinsol_dense.h> /* access to dense SUNLinearSolver */ | ||
7 | #include <arkode/arkode_direct.h> /* access to ARKDls interface */ | ||
8 | #include <sundials/sundials_types.h> /* definition of type realtype */ | ||
9 | #include <sundials/sundials_math.h> | ||
10 | |||
11 | /* Check function return value... | ||
12 | opt == 0 means SUNDIALS function allocates memory so check if | ||
13 | returned NULL pointer | ||
14 | opt == 1 means SUNDIALS function returns a flag so check if | ||
15 | flag >= 0 | ||
16 | opt == 2 means function allocates memory so check if returned | ||
17 | NULL pointer | ||
18 | */ | ||
19 | int check_flag(void *flagvalue, const char *funcname, int opt) | ||
20 | { | ||
21 | int *errflag; | ||
22 | |||
23 | /* Check if SUNDIALS function returned NULL pointer - no memory allocated */ | ||
24 | if (opt == 0 && flagvalue == NULL) { | ||
25 | fprintf(stderr, "\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n", | ||
26 | funcname); | ||
27 | return 1; } | ||
28 | |||
29 | /* Check if flag < 0 */ | ||
30 | else if (opt == 1) { | ||
31 | errflag = (int *) flagvalue; | ||
32 | if (*errflag < 0) { | ||
33 | fprintf(stderr, "\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n", | ||
34 | funcname, *errflag); | ||
35 | return 1; }} | ||
36 | |||
37 | /* Check if function returned NULL pointer - no memory allocated */ | ||
38 | else if (opt == 2 && flagvalue == NULL) { | ||
39 | fprintf(stderr, "\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n", | ||
40 | funcname); | ||
41 | return 1; } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
diff --git a/packages/sundials/src/helpers.h b/packages/sundials/src/helpers.h deleted file mode 100644 index 3d8fbc0..0000000 --- a/packages/sundials/src/helpers.h +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | /* Check function return value... | ||
2 | opt == 0 means SUNDIALS function allocates memory so check if | ||
3 | returned NULL pointer | ||
4 | opt == 1 means SUNDIALS function returns a flag so check if | ||
5 | flag >= 0 | ||
6 | opt == 2 means function allocates memory so check if returned | ||
7 | NULL pointer | ||
8 | */ | ||
9 | int check_flag(void *flagvalue, const char *funcname, int opt); | ||