1- " Abstract supertype of all differential equation solvers."
2- abstract type DiffSolver end
3-
4- " Empty solver for nonlinear discrete-time models."
5- struct EmptySolver <: DiffSolver
6- ni:: Int # number of intermediate stages
7- EmptySolver () = new (- 1 )
8- end
9-
10- """
11- get_solver_functions(NT::DataType, solver::EmptySolver, f!, h!, Ts, nu, nx, ny, nd)
12-
13- Get `solver_f!` and `solver_h!` functions for the `EmptySolver` (discrete models).
14-
15- The functions should have the following signature:
16- ```
17- solver_f!(xnext, k, x, u, d, p) -> nothing
18- solver_h!(y, x, d, p) -> nothing
19- ```
20- in which `xnext`, `k` and `y` arguments are mutated in-place. The `k` argument is
21- a vector of `nx*(solver.ni+1)` elements to store the solver intermediate stage values (and
22- also the current state value for when `supersample ≠ 1`).
23- """
24- function get_solver_functions (:: DataType , :: EmptySolver , f!, h!, _ , _ , _ , _ , _ )
25- solver_f! (xnext, _ , x, u, d, p) = f! (xnext, x, u, d, p)
26- solver_h! = h!
27- return solver_f!, solver_h!
28- end
29-
30- function Base. show (io:: IO , solver:: EmptySolver )
31- print (io, " Empty differential equation solver." )
32- end
33-
34- struct RungeKutta <: DiffSolver
1+ struct RungeKutta{N} <: DiffSolver
352 ni:: Int # number of intermediate stages
36- order:: Int # order of the method
373 supersample:: Int # number of internal steps
384 function RungeKutta (order:: Int , supersample:: Int )
395 if order ≠ 4 && order ≠ 1
@@ -46,7 +12,7 @@ struct RungeKutta <: DiffSolver
4612 throw (ArgumentError (" supersample must be greater than 0" ))
4713 end
4814 ni = order # only true for order ≤ 4 with RungeKutta
49- return new (ni, order , supersample)
15+ return new {order} (ni, supersample)
5016 end
5117end
5218
@@ -61,60 +27,29 @@ This solver is allocation-free if the `f!` and `h!` functions do not allocate.
6127"""
6228RungeKutta (order:: Int = 4 ; supersample:: Int = 1 ) = RungeKutta (order, supersample)
6329
64- " Get `solve_f!` and `solver_h!` functions for the explicit Runge-Kutta solvers."
65- function get_solver_functions (NT:: DataType , solver:: RungeKutta , f!, h!, Ts, _ , nx, _ , _ )
66- solver_f! = if solver. order == 4
67- get_rk4_function (NT, solver, f!, Ts, nx)
68- elseif solver. order == 1
69- get_euler_function (NT, solver, f!, Ts, nx)
70- else
71- throw (ArgumentError (" only 1st and 4th order Runge-Kutta is supported." ))
30+ " Solve the differential equation with the 4th order Runge-Kutta method."
31+ function solver_f! (xnext, k, f!:: F , Ts, solver:: RungeKutta{4} , x, u, d, p) where F
32+ supersample = solver. supersample
33+ Ts_inner = Ts/ supersample
34+ nx = length (x)
35+ xcurr = @views k[1 : nx]
36+ k1 = @views k[(1 nx + 1 ): (2 nx)]
37+ k2 = @views k[(2 nx + 1 ): (3 nx)]
38+ k3 = @views k[(3 nx + 1 ): (4 nx)]
39+ k4 = @views k[(4 nx + 1 ): (5 nx)]
40+ @. xcurr = x
41+ for i= 1 : supersample
42+ f! (k1, xcurr, u, d, p)
43+ @. xnext = xcurr + k1 * Ts_inner/ 2
44+ f! (k2, xnext, u, d, p)
45+ @. xnext = xcurr + k2 * Ts_inner/ 2
46+ f! (k3, xnext, u, d, p)
47+ @. xnext = xcurr + k3 * Ts_inner
48+ f! (k4, xnext, u, d, p)
49+ @. xcurr = xcurr + (k1 + 2 k2 + 2 k3 + k4)* Ts_inner/ 6
7250 end
73- solver_h! = h!
74- return solver_f!, solver_h!
75- end
76-
77- " Get the f! function for the 4th order explicit Runge-Kutta solver."
78- function get_rk4_function (NT, solver, f!, Ts, nx)
79- Ts_inner = Ts/ solver. supersample
80- function rk4_solver_f! (xnext, k, x, u, d, p)
81- xcurr = @views k[1 : nx]
82- k1 = @views k[(1 nx + 1 ): (2 nx)]
83- k2 = @views k[(2 nx + 1 ): (3 nx)]
84- k3 = @views k[(3 nx + 1 ): (4 nx)]
85- k4 = @views k[(4 nx + 1 ): (5 nx)]
86- @. xcurr = x
87- for i= 1 : solver. supersample
88- f! (k1, xcurr, u, d, p)
89- @. xnext = xcurr + k1 * Ts_inner/ 2
90- f! (k2, xnext, u, d, p)
91- @. xnext = xcurr + k2 * Ts_inner/ 2
92- f! (k3, xnext, u, d, p)
93- @. xnext = xcurr + k3 * Ts_inner
94- f! (k4, xnext, u, d, p)
95- @. xcurr = xcurr + (k1 + 2 k2 + 2 k3 + k4)* Ts_inner/ 6
96- end
97- @. xnext = xcurr
98- return nothing
99- end
100- return rk4_solver_f!
101- end
102-
103- " Get the f! function for the explicit Euler solver."
104- function get_euler_function (NT, solver, fc!, Ts, nx)
105- Ts_inner = Ts/ solver. supersample
106- function euler_solver_f! (xnext, k, x, u, d, p)
107- xcurr = @views k[1 : nx]
108- k1 = @views k[(1 nx + 1 ): (2 nx)]
109- @. xcurr = x
110- for i= 1 : solver. supersample
111- fc! (k1, xcurr, u, d, p)
112- @. xcurr = xcurr + k1 * Ts_inner
113- end
114- @. xnext = xcurr
115- return nothing
116- end
117- return euler_solver_f!
51+ @. xnext = xcurr
52+ return nothing
11853end
11954
12055"""
@@ -126,7 +61,24 @@ This is an alias for `RungeKutta(1; supersample)`, see [`RungeKutta`](@ref).
12661"""
12762const ForwardEuler (;supersample= 1 ) = RungeKutta (1 ; supersample)
12863
129- function Base. show (io:: IO , solver:: RungeKutta )
130- N, n = solver. order, solver. supersample
64+
65+ " Solve the differential equation with the forward Euler method."
66+ function solver_f! (xnext, k, f!:: F , Ts, solver:: RungeKutta{1} , x, u, d, p) where F
67+ supersample = solver. supersample
68+ Ts_inner = Ts/ supersample
69+ nx = length (x)
70+ xcurr = @views k[1 : nx]
71+ k1 = @views k[(1 nx + 1 ): (2 nx)]
72+ @. xcurr = x
73+ for i= 1 : supersample
74+ f! (k1, xcurr, u, d, p)
75+ @. xcurr = xcurr + k1 * Ts_inner
76+ end
77+ @. xnext = xcurr
78+ return nothing
79+ end
80+
81+ function Base. show (io:: IO , solver:: RungeKutta{N} ) where N
82+ n = solver. supersample
13183 print (io, " $(N) th order Runge-Kutta differential equation solver with $n supersamples." )
13284end
0 commit comments