pathsim 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. pathsim/__init__.py +3 -0
  2. pathsim/blocks/__init__.py +14 -0
  3. pathsim/blocks/_block.py +209 -0
  4. pathsim/blocks/adder.py +30 -0
  5. pathsim/blocks/amplifier.py +34 -0
  6. pathsim/blocks/delay.py +70 -0
  7. pathsim/blocks/differentiator.py +70 -0
  8. pathsim/blocks/function.py +82 -0
  9. pathsim/blocks/integrator.py +66 -0
  10. pathsim/blocks/lti.py +155 -0
  11. pathsim/blocks/multiplier.py +30 -0
  12. pathsim/blocks/ode.py +86 -0
  13. pathsim/blocks/rf/__init__.py +4 -0
  14. pathsim/blocks/rf/filters.py +169 -0
  15. pathsim/blocks/rf/noise.py +218 -0
  16. pathsim/blocks/rf/sources.py +163 -0
  17. pathsim/blocks/rf/wienerhammerstein.py +338 -0
  18. pathsim/blocks/rng.py +57 -0
  19. pathsim/blocks/scope.py +224 -0
  20. pathsim/blocks/sources.py +71 -0
  21. pathsim/blocks/spectrum.py +316 -0
  22. pathsim/connection.py +112 -0
  23. pathsim/simulation.py +652 -0
  24. pathsim/solvers/__init__.py +25 -0
  25. pathsim/solvers/_solver.py +403 -0
  26. pathsim/solvers/bdf.py +240 -0
  27. pathsim/solvers/dirk2.py +101 -0
  28. pathsim/solvers/dirk3.py +86 -0
  29. pathsim/solvers/esdirk32.py +131 -0
  30. pathsim/solvers/esdirk4.py +99 -0
  31. pathsim/solvers/esdirk43.py +139 -0
  32. pathsim/solvers/esdirk54.py +141 -0
  33. pathsim/solvers/esdirk85.py +200 -0
  34. pathsim/solvers/euler.py +81 -0
  35. pathsim/solvers/rk4.py +61 -0
  36. pathsim/solvers/rkbs32.py +101 -0
  37. pathsim/solvers/rkck54.py +108 -0
  38. pathsim/solvers/rkdp54.py +111 -0
  39. pathsim/solvers/rkdp87.py +116 -0
  40. pathsim/solvers/rkf45.py +102 -0
  41. pathsim/solvers/rkf78.py +111 -0
  42. pathsim/solvers/rkv65.py +103 -0
  43. pathsim/solvers/ssprk22.py +62 -0
  44. pathsim/solvers/ssprk33.py +65 -0
  45. pathsim/solvers/ssprk34.py +74 -0
  46. pathsim/subsystem.py +267 -0
  47. pathsim/utils/__init__.py +0 -0
  48. pathsim/utils/adaptivebuffer.py +87 -0
  49. pathsim/utils/anderson.py +180 -0
  50. pathsim/utils/funcs.py +205 -0
  51. pathsim/utils/gilbert.py +110 -0
  52. pathsim/utils/progresstracker.py +90 -0
  53. pathsim/utils/realtimeplotter.py +230 -0
  54. pathsim/utils/statespacerealizations.py +116 -0
  55. pathsim/utils/waveforms.py +36 -0
  56. pathsim-0.2.0.dist-info/LICENSE.txt +21 -0
  57. pathsim-0.2.0.dist-info/METADATA +149 -0
  58. pathsim-0.2.0.dist-info/RECORD +109 -0
  59. pathsim-0.2.0.dist-info/WHEEL +5 -0
  60. pathsim-0.2.0.dist-info/top_level.txt +2 -0
  61. tests/__init__.py +0 -0
  62. tests/blocks/__init__.py +0 -0
  63. tests/blocks/test_adder.py +85 -0
  64. tests/blocks/test_amplifier.py +66 -0
  65. tests/blocks/test_block.py +138 -0
  66. tests/blocks/test_delay.py +122 -0
  67. tests/blocks/test_differentiator.py +102 -0
  68. tests/blocks/test_function.py +165 -0
  69. tests/blocks/test_integrator.py +92 -0
  70. tests/blocks/test_lti.py +162 -0
  71. tests/blocks/test_multiplier.py +87 -0
  72. tests/blocks/test_ode.py +125 -0
  73. tests/blocks/test_rng.py +109 -0
  74. tests/blocks/test_scope.py +196 -0
  75. tests/blocks/test_sources.py +119 -0
  76. tests/blocks/test_spectrum.py +119 -0
  77. tests/solvers/__init__.py +0 -0
  78. tests/solvers/test_bdf.py +364 -0
  79. tests/solvers/test_dirk2.py +138 -0
  80. tests/solvers/test_dirk3.py +137 -0
  81. tests/solvers/test_esdirk32.py +158 -0
  82. tests/solvers/test_esdirk4.py +138 -0
  83. tests/solvers/test_esdirk43.py +158 -0
  84. tests/solvers/test_esdirk54.py +160 -0
  85. tests/solvers/test_esdirk85.py +157 -0
  86. tests/solvers/test_euler.py +223 -0
  87. tests/solvers/test_rk4.py +138 -0
  88. tests/solvers/test_rkbs32.py +159 -0
  89. tests/solvers/test_rkck54.py +157 -0
  90. tests/solvers/test_rkdp54.py +159 -0
  91. tests/solvers/test_rkdp87.py +157 -0
  92. tests/solvers/test_rkf45.py +159 -0
  93. tests/solvers/test_rkf78.py +160 -0
  94. tests/solvers/test_rkv65.py +160 -0
  95. tests/solvers/test_solver.py +119 -0
  96. tests/solvers/test_ssprk22.py +136 -0
  97. tests/solvers/test_ssprk33.py +136 -0
  98. tests/solvers/test_ssprk34.py +136 -0
  99. tests/test_connection.py +176 -0
  100. tests/test_simulation.py +271 -0
  101. tests/test_subsystem.py +182 -0
  102. tests/utils/__init__.py +0 -0
  103. tests/utils/test_adaptivebuffer.py +111 -0
  104. tests/utils/test_anderson.py +142 -0
  105. tests/utils/test_funcs.py +143 -0
  106. tests/utils/test_gilbert.py +108 -0
  107. tests/utils/test_progresstracker.py +144 -0
  108. tests/utils/test_realtimeplotter.py +122 -0
  109. tests/utils/test_statespacerealizations.py +107 -0
@@ -0,0 +1,116 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT ADAPTIVE TIMESTEPPING RUNGE-KUTTA INTEGRATORS
4
+ ## (solvers/rkf78.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import numpy as np
13
+
14
+ from ._solver import ExplicitSolver
15
+
16
+
17
+ # SOLVERS ==============================================================================
18
+
19
+ class RKDP87(ExplicitSolver):
20
+ """
21
+ 13-stage 8-th order embedded Runge-Kutta method from Dormand and Prince
22
+ with embedded 7-th order method for 8-th order truncation error estimate
23
+ that can be used to adaptively control the timestep.
24
+
25
+ This solver is a great choice if extremely high accuracy is required.
26
+ """
27
+
28
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
29
+ super().__init__(initial_value, func, jac, tolerance_lte)
30
+
31
+ #counter for runge kutta stages
32
+ self.stage = 0
33
+
34
+ #flag adaptive timestep solver
35
+ self.is_adaptive = True
36
+
37
+ #slope coefficients for stages
38
+ self.Ks = {}
39
+
40
+ #intermediate evaluation times
41
+ self.eval_stages = [0.0, 1/18, 1/12, 1/8, 5/16, 3/8, 59/400, 93/200, 5490023248/9719169821, 13/20, 1201146811/1299019798, 1.0, 1.0]
42
+
43
+ #extended butcher table
44
+ self.BT = {0:[1/18],
45
+ 1:[1/48, 1/16],
46
+ 2:[1/32, 0, 3/32],
47
+ 3:[5/16, 0, -75/64, 75/64],
48
+ 4:[3/80, 0, 0, 3/16, 3/20],
49
+ 5:[29443841/614563906, 0, 0, 77736538/692538347, -28693883/1125000000, 23124283/1800000000],
50
+ 6:[16016141/946692911, 0, 0, 61564180/158732637, 22789713/633445777, 545815736/2771057229, -180193667/1043307555],
51
+ 7:[39632708/573591083, 0, 0, -433636366/683701615, -421739975/2616292301, 100302831/723423059, 790204164/839813087, 800635310/3783071287],
52
+ 8:[246121993/1340847787, 0, 0, -37695042795/15268766246, -309121744/1061227803, -12992083/490766935, 6005943493/2108947869, 393006217/1396673457, 123872331/1001029789],
53
+ 9:[-1028468189/846180014, 0, 0, 8478235783/508512852, 1311729495/1432422823, -10304129995/1701304382, -48777925059/3047939560, 15336726248/1032824649, -45442868181/3398467696, 3065993473/597172653],
54
+ 10:[185892177/718116043, 0, 0, -3185094517/667107341, -477755414/1098053517, -703635378/230739211, 5731566787/1027545527, 5232866602/850066563, -4093664535/808688257, 3962137247/1805957418, 65686358/487910083],
55
+ 11:[403863854/491063109, 0, 0, -5068492393/434740067, -411421997/543043805, 652783627/914296604, 11173962825/925320556, -13158990841/6184727034, 3936647629/1978049680, -160528059/685178525, 248638103/1413531060, 0],
56
+ 12:[14005451/335480064, 0, 0, 0, 0, -59238493/1068277825, 181606767/758867731, 561292985/797845732, -1041891430/1371343529, 760417239/1151165299, 118820643/751138087, -528747749/2220607170, 1/4]}
57
+
58
+ #coefficients for lower order solution evaluation
59
+ self.bh = [13451932/455176623, 0, 0, 0, 0, -808719846/976000145, 1757004468/5645159321, 656045339/265891186, -3867574721/1518517206, 465885868/322736535, 53011238/667516719, 2/45, 0]
60
+
61
+ #lower order solution
62
+ self.xh = None
63
+
64
+
65
+ def error_controller(self, dt):
66
+ """
67
+ compute scaling factor for adaptive timestep
68
+ based on local truncation error estimate and returns both
69
+ """
70
+ if self.xh is None:
71
+ return True, 0.0, 1.0
72
+
73
+ #compute and clip truncation error
74
+ truncation_error = np.max(np.clip(abs(self.x-self.xh), 1e-18, None))
75
+
76
+ #compute error ratio
77
+ error_ratio = self.tolerance_lte / truncation_error
78
+ success = error_ratio >= 1.0
79
+
80
+ #compute timestep scale
81
+ timestep_rescale = 0.9 * (error_ratio)**(1/8)
82
+
83
+ return success, truncation_error, timestep_rescale
84
+
85
+
86
+ def step(self, u, t, dt):
87
+ """
88
+ performs the (explicit) timestep for (t+dt)
89
+ based on the state and input at (t)
90
+ """
91
+
92
+ #buffer intermediate slope
93
+ self.Ks[self.stage] = self.func(self.x, u, t)
94
+
95
+ #update state at stage
96
+ slope = 0.0
97
+ for i, b in enumerate(self.BT[self.stage]):
98
+ slope += self.Ks[i] * b
99
+ self.x = dt * slope + self.x_0
100
+
101
+ #error and step size control
102
+ if self.stage < 12:
103
+ self.stage += 1
104
+ return True, 0.0, 1.0
105
+
106
+ else:
107
+
108
+ #lower order solution
109
+ slope = 0.0
110
+ for i, bh in enumerate( self.bh):
111
+ slope += self.Ks[i] * bh
112
+ self.xh = dt * slope + self.x_0
113
+
114
+ #reset stage counter
115
+ self.stage = 0
116
+ return self.error_controller(dt)
@@ -0,0 +1,102 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT ADAPTIVE TIMESTEPPING RUNGE-KUTTA INTEGRATORS
4
+ ## (solvers/rkf45.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import numpy as np
13
+
14
+ from ._solver import ExplicitSolver
15
+
16
+
17
+ # SOLVERS ==============================================================================
18
+
19
+ class RKF45(ExplicitSolver):
20
+ """
21
+ 6-stage 4-th order embedded Runge-Kutta-Fehlberg method
22
+ with 5-th order truncation error estimate that can be used to
23
+ adaptively control the timestep.
24
+
25
+ Absolute classic but relatively slow.
26
+ """
27
+
28
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
29
+ super().__init__(initial_value, func, jac, tolerance_lte)
30
+
31
+ #counter for runge kutta stages
32
+ self.stage = 0
33
+
34
+ #flag adaptive timestep solver
35
+ self.is_adaptive = True
36
+
37
+ #slope coefficients for stages
38
+ self.Ks = {}
39
+
40
+ #intermediate evaluation times
41
+ self.eval_stages = [0.0, 1/4, 3/8, 12/13, 1, 1/2]
42
+
43
+ #extended butcher table
44
+ self.BT = {0:[ 1/4],
45
+ 1:[ 3/32, 9/32],
46
+ 2:[1932/2197, -7200/2197, 7296/2197],
47
+ 3:[ 439/216, -8, 3680/513, -845/4104],
48
+ 4:[ -8/27, 2, -3554/2565, 1859/4104, -11/40],
49
+ 5:[ 25/216, 0, 1408/2565, 2197/4104, -1/5, 0]}
50
+
51
+ #coefficients for local truncation error estimate
52
+ self.TR = [1/360, 0, -128/4275, -2197/75240, 1/50, 2/55]
53
+
54
+
55
+ def error_controller(self, dt):
56
+ """
57
+ compute scaling factor for adaptive timestep
58
+ based on local truncation error estimate and returns both
59
+ """
60
+ if len(self.Ks)<len(self.TR):
61
+ return True, 0.0, 1.0
62
+
63
+ #compute local truncation error slope
64
+ slope = 0.0
65
+ for i, b in enumerate(self.TR):
66
+ slope += self.Ks[i] * b
67
+
68
+ #compute and clip truncation error
69
+ truncation_error = np.max(np.clip(abs(dt*slope), 1e-18, None))
70
+
71
+ #compute error ratio
72
+ error_ratio = self.tolerance_lte / truncation_error
73
+ success = error_ratio >= 1.0
74
+
75
+ #compute timestep scale
76
+ timestep_rescale = 0.9 * (error_ratio)**(1/5)
77
+
78
+ return success, truncation_error, timestep_rescale
79
+
80
+
81
+ def step(self, u, t, dt):
82
+ """
83
+ performs the (explicit) timestep for (t+dt)
84
+ based on the state and input at (t)
85
+ """
86
+
87
+ #buffer intermediate slope
88
+ self.Ks[self.stage] = self.func(self.x, u, t)
89
+
90
+ #update state at stage
91
+ slope = 0.0
92
+ for i, b in enumerate(self.BT[self.stage]):
93
+ slope += self.Ks[i] * b
94
+ self.x = dt * slope + self.x_0
95
+
96
+ #error and step size control
97
+ if self.stage < 5:
98
+ self.stage += 1
99
+ return True, 0.0, 1.0
100
+ else:
101
+ self.stage = 0
102
+ return self.error_controller(dt)
@@ -0,0 +1,111 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT ADAPTIVE TIMESTEPPING RUNGE-KUTTA INTEGRATORS
4
+ ## (solvers/rkf78.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import numpy as np
13
+
14
+ from ._solver import ExplicitSolver
15
+
16
+
17
+ # SOLVERS ==============================================================================
18
+
19
+ class RKF78(ExplicitSolver):
20
+ """
21
+ 13-stage 7-th order embedded Runge-Kutta-Fehlberg method
22
+ with 8-th order truncation error estimate that can be used to
23
+ adaptively control the timestep.
24
+
25
+ This solver is a great choice if extremely high accuracy is required.
26
+ It is also almost symplectic and therefore quite suitable for
27
+ conservation systems such as celestial dynamics, etc.
28
+ """
29
+
30
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
31
+ super().__init__(initial_value, func, jac, tolerance_lte)
32
+
33
+ #counter for runge kutta stages
34
+ self.stage = 0
35
+
36
+ #flag adaptive timestep solver
37
+ self.is_adaptive = True
38
+
39
+ #slope coefficients for stages
40
+ self.Ks = {}
41
+
42
+ #intermediate evaluation times
43
+ self.eval_stages = [0, 2/27, 1/9, 1/6, 5/12, 1/2, 5/6, 1/6, 2/3, 1/3, 1, 0, 1]
44
+
45
+ #extended butcher table
46
+ self.BT = {0: [ 2/27],
47
+ 1: [ 1/36, 1/12],
48
+ 2: [ 1/24, 0, 1/8],
49
+ 3: [ 5/12, 0, -25/16, 25/16],
50
+ 4: [ 1/20, 0, 0, 1/4, 1/5],
51
+ 5: [ -25/108, 0, 0, 125/108, -65/27, 125/54],
52
+ 6: [ 31/300, 0, 0, 0, 61/225, -2/9, 13/900],
53
+ 7: [ 2, 0, 0, -53/6, 704/45, -107/9, 67/90, 3],
54
+ 8: [ -91/108, 0, 0, 23/108, -976/135, 311/54, -19/60, 17/6, -1/12],
55
+ 9: [ 2383/4100, 0, 0, -341/164, 4496/1025, -301/82, 2133/4100, 45/82, 45/164, 18/41],
56
+ 10:[ 3/205, 0, 0, 0, 0, -6/41, -3/205, -3/41, 3/41, 6/41],
57
+ 11:[-1777/4100, 0, 0, -341/164, 4496/1025, -289/82, 2193/4100, 51/82, 33/164, 12/41, 0, 1],
58
+ 12:[ 41/840, 0, 0, 0, 0, 34/105, 9/35, 9/35, 9/280, 9/280, 41/840]}
59
+
60
+ #coefficients for local truncation error estimate
61
+ self.TR = [41/840, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41/840, -41/840, -41/840]
62
+
63
+
64
+ def error_controller(self, dt):
65
+ """
66
+ compute scaling factor for adaptive timestep
67
+ based on local truncation error estimate and returns both
68
+ """
69
+ if len(self.Ks)<len(self.TR):
70
+ return True, 0.0, 1.0
71
+
72
+ #compute local truncation error slope
73
+ slope = 0.0
74
+ for i, b in enumerate(self.TR):
75
+ slope += self.Ks[i] * b
76
+
77
+ #compute and clip truncation error
78
+ truncation_error = np.max(np.clip(abs(dt*slope), 1e-18, None))
79
+
80
+ #compute error ratio
81
+ error_ratio = self.tolerance_lte / truncation_error
82
+ success = error_ratio >= 1.0
83
+
84
+ #compute timestep scale
85
+ timestep_rescale = 0.9 * (error_ratio)**(1/8)
86
+
87
+ return success, truncation_error, timestep_rescale
88
+
89
+
90
+ def step(self, u, t, dt):
91
+ """
92
+ performs the (explicit) timestep for (t+dt)
93
+ based on the state and input at (t)
94
+ """
95
+
96
+ #buffer intermediate slope
97
+ self.Ks[self.stage] = self.func(self.x, u, t)
98
+
99
+ #update state at stage
100
+ slope = 0.0
101
+ for i, b in enumerate(self.BT[self.stage]):
102
+ slope += self.Ks[i] * b
103
+ self.x = dt * slope + self.x_0
104
+
105
+ #error and step size control
106
+ if self.stage < 12:
107
+ self.stage += 1
108
+ return True, 0.0, 1.0
109
+ else:
110
+ self.stage = 0
111
+ return self.error_controller(dt)
@@ -0,0 +1,103 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT ADAPTIVE TIMESTEPPING RUNGE-KUTTA INTEGRATORS
4
+ ## (solvers/rkv65.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import numpy as np
13
+
14
+ from ._solver import ExplicitSolver
15
+
16
+
17
+ # SOLVERS ==============================================================================
18
+
19
+ class RKV65(ExplicitSolver):
20
+ """
21
+ 9-stage 6-th order with embedded 5-th order Runge-Kutta method from Verner
22
+ with 6-th order truncation error estimate.
23
+
24
+ This is the 'most robust' 9, 6(5) pair of Jim Verner's Refuge for Runge-Kutta Pairs
25
+ URL: https://www.sfu.ca/~jverner/
26
+ """
27
+
28
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
29
+ super().__init__(initial_value, func, jac, tolerance_lte)
30
+
31
+ #counter for runge kutta stages
32
+ self.stage = 0
33
+
34
+ #flag adaptive timestep solver
35
+ self.is_adaptive = True
36
+
37
+ #slope coefficients for stages
38
+ self.Ks = {}
39
+
40
+ #intermediate evaluation times
41
+ self.eval_stages = [0.0, 9/50, 1/6, 1/4, 53/100, 3/5, 4/5, 1.0, 1.0]
42
+
43
+ #extended butcher table
44
+ self.BT = {0:[ 9/50],
45
+ 1:[ 29/324, 25/324],
46
+ 2:[ 1/16, 0, 3/16],
47
+ 3:[ 79129/250000, 0, -261237/250000, 19663/15625],
48
+ 4:[ 1336883/4909125, 0, -25476/30875, 194159/185250, 8225/78546],
49
+ 5:[-2459386/14727375, 0, 19504/30875, 2377474/13615875, -6157250/5773131, 902/735],
50
+ 6:[ 2699/7410, 0, -252/1235, -1393253/3993990, 236875/72618, -135/49, 15/22],
51
+ 7:[ 11/144, 0, 0, 256/693, 0, 125/504, 125/528, 5/72],
52
+ 8:[ 28/477, 0, 0, 212/441, -312500/366177, 2125/1764, 0, -2105/35532, 2995/17766]}
53
+
54
+ #5-th order solution at stage 9
55
+ self.xh = None
56
+
57
+
58
+ def error_controller(self, dt):
59
+ """
60
+ compute scaling factor for adaptive timestep
61
+ based on local truncation error estimate and returns both
62
+ """
63
+ if self.xh is None:
64
+ return True, 0.0, 1.0
65
+
66
+ #compute and clip truncation error
67
+ truncation_error = np.max(np.clip(abs(self.x-self.xh), 1e-18, None))
68
+
69
+ #compute error ratio
70
+ error_ratio = self.tolerance_lte / truncation_error
71
+ success = error_ratio >= 1.0
72
+
73
+ #compute timestep scale
74
+ timestep_rescale = 0.9 * (error_ratio)**(1/6)
75
+
76
+ return success, truncation_error, timestep_rescale
77
+
78
+
79
+ def step(self, u, t, dt):
80
+ """
81
+ performs the (explicit) timestep for (t+dt)
82
+ based on the state and input at (t)
83
+ """
84
+
85
+ #buffer intermediate slope
86
+ self.Ks[self.stage] = self.func(self.x, u, t)
87
+
88
+ #compute slope at stage
89
+ slope = 0.0
90
+ for i, b in enumerate(self.BT[self.stage]):
91
+ slope += self.Ks[i] * b
92
+
93
+ #error and step size control
94
+ if self.stage < 8:
95
+ #stepping with 6-th order solution
96
+ self.x = dt * slope + self.x_0
97
+ self.stage += 1
98
+ return True, 0.0, 1.0
99
+ else:
100
+ #save 5-th order solution for error control at last stage
101
+ self.xh = dt * slope + self.x_0
102
+ self.stage = 0
103
+ return self.error_controller(dt)
@@ -0,0 +1,62 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT STRONG STABILITY PRESERVING RUNGE-KUTTA INTEGRATOR
4
+ ## (solvers/ssprk22.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ from ._solver import ExplicitSolver
13
+
14
+
15
+ # SOLVERS ==============================================================================
16
+
17
+ class SSPRK22(ExplicitSolver):
18
+ """
19
+ Strong Stability Preserving (SSP) 2-nd order two stage (2,2) Runge-Kutta method,
20
+ also known as the 'Heun-Method'.
21
+
22
+ This integrator has a good trade off between speed, accuracy and stability.
23
+ Especially for non-stiff linear systems, this is probably a great choice.
24
+ """
25
+
26
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
27
+ super().__init__(initial_value, func, jac, tolerance_lte)
28
+
29
+ #counter for runge kutta stages
30
+ self.stage = 0
31
+
32
+ #slope coefficients for stages
33
+ self.Ks = {}
34
+
35
+ #intermediate evaluation times
36
+ self.eval_stages = [0.0, 1.0]
37
+
38
+ #butcher table
39
+ self.BT = {0:[1.0],
40
+ 1:[1/2, 1/2]}
41
+
42
+
43
+ def step(self, u, t, dt):
44
+ """
45
+ performs the (explicit) timestep for (t+dt)
46
+ based on the state and input at (t)
47
+ """
48
+
49
+ #buffer intermediate slope
50
+ self.Ks[self.stage] = self.func(self.x, u, t)
51
+
52
+ #update state at stage
53
+ slope = 0.0
54
+ for i, b in enumerate(self.BT[self.stage]):
55
+ slope += self.Ks[i] * b
56
+ self.x = dt * slope + self.x_0
57
+
58
+ #wrap around stage counter
59
+ self.stage = (self.stage + 1) % 2
60
+
61
+ #no error estimate available
62
+ return True, 0.0, 1.0
@@ -0,0 +1,65 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT STRONG STABILITY PRESERVING RUNGE-KUTTA INTEGRATOR
4
+ ## (solvers/ssprk33.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ from ._solver import ExplicitSolver
13
+
14
+
15
+ # SOLVERS ==============================================================================
16
+
17
+ class SSPRK33(ExplicitSolver):
18
+ """
19
+ Strong Stability Preserving (SSP) 3-rd order
20
+ three stage (3,3) Runge-Kutta method
21
+
22
+ This integrator is more accurate and stable then SSPRK22 but
23
+ also 50% more expensive due to 3 instead of 2 stages.
24
+ Originally designed for hyperbolic PDEs, this is also a great
25
+ choice if accuracy and stability and still good speed are important.
26
+ """
27
+
28
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
29
+ super().__init__(initial_value, func, jac, tolerance_lte)
30
+
31
+ #counter for runge kutta stages
32
+ self.stage = 0
33
+
34
+ #slope coefficients for stages
35
+ self.Ks = {}
36
+
37
+ #intermediate evaluation times
38
+ self.eval_stages = [0.0, 1.0, 0.5]
39
+
40
+ #butcher table
41
+ self.BT = {0:[1.0],
42
+ 1:[1/4, 1/4],
43
+ 2:[1/6, 1/6, 2/3]}
44
+
45
+
46
+ def step(self, u, t, dt):
47
+ """
48
+ performs the (explicit) timestep for (t+dt)
49
+ based on the state and input at (t)
50
+ """
51
+
52
+ #buffer intermediate slope
53
+ self.Ks[self.stage] = self.func(self.x, u, t)
54
+
55
+ #update state at stage
56
+ slope = 0.0
57
+ for i, b in enumerate(self.BT[self.stage]):
58
+ slope += self.Ks[i] * b
59
+ self.x = dt * slope + self.x_0
60
+
61
+ #wrap around stage counter
62
+ self.stage = (self.stage + 1) % 3
63
+
64
+ #no error estimate available
65
+ return True, 0.0, 1.0
@@ -0,0 +1,74 @@
1
+ ########################################################################################
2
+ ##
3
+ ## EXPLICIT STRONG STABILITY PRESERVING RUNGE-KUTTA INTEGRATOR
4
+ ## (solvers/ssprk34.py)
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ # import numpy as np
13
+
14
+ from ._solver import ExplicitSolver
15
+
16
+
17
+ # SOLVERS ==============================================================================
18
+
19
+ class SSPRK34(ExplicitSolver):
20
+ """
21
+ Strong Stability Preserving (SSP) 3-rd order 4 stage
22
+ (3,4) Runge-Kutta method
23
+
24
+ This integrator has one stage more then SSPRK33 but is also
25
+ 3-rd order. So in terms or accuracy, they are the same but
26
+ the 4-th stage gives quite a lot more stability.
27
+ The stability region includes the point -4 on the real axis
28
+ and is even more stable then the classical 'RK4' method in
29
+ this aspect. But again it is 33% more expensive then SSPRK33
30
+ due to the additional stage.
31
+
32
+ If super high stability is required, this might be a good
33
+ choice.
34
+ """
35
+
36
+ def __init__(self, initial_value=0, func=lambda x, u, t: u, jac=None, tolerance_lte=1e-6):
37
+ super().__init__(initial_value, func, jac, tolerance_lte)
38
+
39
+ #counter for runge kutta stages
40
+ self.stage = 0
41
+
42
+ #slope coefficients for stages
43
+ self.Ks = {}
44
+
45
+ #intermediate evaluation times
46
+ self.eval_stages = [0.0, 1/2, 1, 1/2]
47
+
48
+ #butcher table
49
+ self.BT = {0:[1/2],
50
+ 1:[1/2, 1/2],
51
+ 2:[1/6, 1/6, 1/6],
52
+ 3:[1/6, 1/6, 1/6, 1/2]}
53
+
54
+
55
+ def step(self, u, t, dt):
56
+ """
57
+ performs the (explicit) timestep for (t+dt)
58
+ based on the state and input at (t)
59
+ """
60
+
61
+ #buffer intermediate slope
62
+ self.Ks[self.stage] = self.func(self.x, u, t)
63
+
64
+ #update state at stage
65
+ slope = 0.0
66
+ for i, b in enumerate(self.BT[self.stage]):
67
+ slope += self.Ks[i] * b
68
+ self.x = dt * slope + self.x_0
69
+
70
+ #wrap around stage counter
71
+ self.stage = (self.stage + 1) % 4
72
+
73
+ #no error estimate available
74
+ return True, 0.0, 1.0