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,138 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/dirk2.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.solvers.dirk2 import DIRK2
16
+
17
+
18
+
19
+ # TEST PROBLEMS ========================================================================
20
+
21
+ class Problem:
22
+ def __init__(self, name, func, jac, x0, solution):
23
+ self.name = name
24
+ self.func = func
25
+ self.jac = jac
26
+ self.x0 = x0
27
+ self.solution = solution
28
+
29
+
30
+ #create some reference problems for testing
31
+ reference_problems = [
32
+ Problem(name="linear_feedback",
33
+ func=lambda x, u, t: -x,
34
+ jac=lambda x, u, t: -1,
35
+ x0=1.0,
36
+ solution=lambda t: np.exp(-t)
37
+ ),
38
+ Problem(name="logistic",
39
+ func=lambda x, u, t: x*(1-x),
40
+ jac=lambda x, u, t: 1-2*x,
41
+ x0=0.5,
42
+ solution=lambda t: 1/(1 + np.exp(-t))
43
+ )
44
+ ]
45
+
46
+
47
+ # TESTS ================================================================================
48
+
49
+ class TestDIRK2(unittest.TestCase):
50
+ """
51
+ Test the implementation of the 'DIRK2' solver class
52
+ """
53
+
54
+ def test_init(self):
55
+
56
+ #test default initializtion
57
+ solver = DIRK2()
58
+
59
+ self.assertTrue(callable(solver.func))
60
+ self.assertEqual(solver.jac, None)
61
+ self.assertEqual(solver.initial_value, 0)
62
+
63
+ self.assertEqual(solver.stage, 0)
64
+ self.assertFalse(solver.is_adaptive)
65
+ self.assertTrue(solver.is_implicit)
66
+ self.assertFalse(solver.is_explicit)
67
+
68
+ #test specific initialization
69
+ solver = DIRK2(initial_value=1,
70
+ func=lambda x, u, t: -x,
71
+ jac=lambda x, u, t: -1,
72
+ tolerance_lte=1e-6)
73
+
74
+ self.assertEqual(solver.func(2, 0, 0), -2)
75
+ self.assertEqual(solver.jac(2, 0, 0), -1)
76
+ self.assertEqual(solver.initial_value, 1)
77
+ self.assertEqual(solver.tolerance_lte, 1e-6)
78
+
79
+
80
+ def test_stages(self):
81
+
82
+ solver = DIRK2()
83
+
84
+ for i, t in enumerate(solver.stages(0, 1)):
85
+
86
+ #test the stage iterator
87
+ self.assertEqual(t, solver.eval_stages[i])
88
+
89
+
90
+ def test_step(self):
91
+
92
+ solver = DIRK2()
93
+
94
+ for i, t in enumerate(solver.stages(0, 1)):
95
+
96
+ #test if stage incrementation works
97
+ self.assertEqual(solver.stage, i)
98
+
99
+ _ = solver.solve(0.0, t, 1) #needed for implicit solvers to get slope
100
+ success, err, scale = solver.step(0.0, t, 1)
101
+
102
+ #test if expected return at intermediate stages
103
+ self.assertTrue(success)
104
+ self.assertEqual(err, 0.0)
105
+ self.assertEqual(scale, 1.0)
106
+
107
+
108
+ def test_integrate_fixed(self):
109
+
110
+ #integrate test problem and assess convergence order
111
+
112
+ timesteps = np.logspace(-1, -0.2, 10)
113
+
114
+ for problem in reference_problems:
115
+
116
+ solver = DIRK2(problem.x0, problem.func, problem.jac)
117
+
118
+ errors = []
119
+
120
+ for dt in timesteps:
121
+
122
+ solver.reset()
123
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
124
+
125
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
126
+
127
+ #test if errors are monotonically decreasing
128
+ self.assertTrue(np.all(np.diff(errors)>0))
129
+
130
+ #test convergence order, expected 2 or 3
131
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
132
+ self.assertEqual(round(p), 2)
133
+
134
+
135
+ # RUN TESTS LOCALLY ====================================================================
136
+
137
+ if __name__ == '__main__':
138
+ unittest.main(verbosity=2)
@@ -0,0 +1,137 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/dirk3.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.solvers.dirk3 import DIRK3
16
+
17
+
18
+ # TEST PROBLEMS ========================================================================
19
+
20
+ class Problem:
21
+ def __init__(self, name, func, jac, x0, solution):
22
+ self.name = name
23
+ self.func = func
24
+ self.jac = jac
25
+ self.x0 = x0
26
+ self.solution = solution
27
+
28
+
29
+ #create some reference problems for testing
30
+ reference_problems = [
31
+ Problem(name="linear_feedback",
32
+ func=lambda x, u, t: -x,
33
+ jac=lambda x, u, t: -1,
34
+ x0=1.0,
35
+ solution=lambda t: np.exp(-t)
36
+ ),
37
+ Problem(name="logistic",
38
+ func=lambda x, u, t: x*(1-x),
39
+ jac=lambda x, u, t: 1-2*x,
40
+ x0=0.5,
41
+ solution=lambda t: 1/(1 + np.exp(-t))
42
+ )
43
+ ]
44
+
45
+
46
+ # TESTS ================================================================================
47
+
48
+ class TestDIRK3(unittest.TestCase):
49
+ """
50
+ Test the implementation of the 'DIRK3' solver class
51
+ """
52
+
53
+ def test_init(self):
54
+
55
+ #test default initializtion
56
+ solver = DIRK3()
57
+
58
+ self.assertTrue(callable(solver.func))
59
+ self.assertEqual(solver.jac, None)
60
+ self.assertEqual(solver.initial_value, 0)
61
+
62
+ self.assertEqual(solver.stage, 0)
63
+ self.assertFalse(solver.is_adaptive)
64
+ self.assertTrue(solver.is_implicit)
65
+ self.assertFalse(solver.is_explicit)
66
+
67
+ #test specific initialization
68
+ solver = DIRK3(initial_value=1,
69
+ func=lambda x, u, t: -x,
70
+ jac=lambda x, u, t: -1,
71
+ tolerance_lte=1e-6)
72
+
73
+ self.assertEqual(solver.func(2, 0, 0), -2)
74
+ self.assertEqual(solver.jac(2, 0, 0), -1)
75
+ self.assertEqual(solver.initial_value, 1)
76
+ self.assertEqual(solver.tolerance_lte, 1e-6)
77
+
78
+
79
+ def test_stages(self):
80
+
81
+ solver = DIRK3()
82
+
83
+ for i, t in enumerate(solver.stages(0, 1)):
84
+
85
+ #test the stage iterator
86
+ self.assertEqual(t, solver.eval_stages[i])
87
+
88
+
89
+ def test_step(self):
90
+
91
+ solver = DIRK3()
92
+
93
+ for i, t in enumerate(solver.stages(0, 1)):
94
+
95
+ #test if stage incrementation works
96
+ self.assertEqual(solver.stage, i)
97
+
98
+ _ = solver.solve(0.0, t, 1) #needed for implicit solvers to get slope
99
+ success, err, scale = solver.step(0.0, t, 1)
100
+
101
+ #test if expected return at intermediate stages
102
+ self.assertTrue(success)
103
+ self.assertEqual(err, 0.0)
104
+ self.assertEqual(scale, 1.0)
105
+
106
+
107
+ def test_integrate_fixed(self):
108
+
109
+ #integrate test problem and assess convergence order
110
+
111
+ timesteps = np.logspace(-1, -0.2, 10)
112
+
113
+ for problem in reference_problems:
114
+
115
+ solver = DIRK3(problem.x0, problem.func, problem.jac)
116
+
117
+ errors = []
118
+
119
+ for dt in timesteps:
120
+
121
+ solver.reset()
122
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
123
+
124
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
125
+
126
+ #test if errors are monotonically decreasing
127
+ self.assertTrue(np.all(np.diff(errors)>0))
128
+
129
+ #test convergence order, expected 2 or 3
130
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
131
+ self.assertGreater(p, 2.4)
132
+
133
+
134
+ # RUN TESTS LOCALLY ====================================================================
135
+
136
+ if __name__ == '__main__':
137
+ unittest.main(verbosity=2)
@@ -0,0 +1,158 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/esdirk32.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.solvers.esdirk32 import ESDIRK32
16
+
17
+
18
+ # TEST PROBLEMS ========================================================================
19
+
20
+ class Problem:
21
+ def __init__(self, name, func, jac, x0, solution):
22
+ self.name = name
23
+ self.func = func
24
+ self.jac = jac
25
+ self.x0 = x0
26
+ self.solution = solution
27
+
28
+
29
+ #create some reference problems for testing
30
+ reference_problems = [
31
+ Problem(name="linear_feedback",
32
+ func=lambda x, u, t: -x,
33
+ jac=lambda x, u, t: -1,
34
+ x0=1.0,
35
+ solution=lambda t: np.exp(-t)
36
+ ),
37
+ Problem(name="logistic",
38
+ func=lambda x, u, t: x*(1-x),
39
+ jac=lambda x, u, t: 1-2*x,
40
+ x0=0.5,
41
+ solution=lambda t: 1/(1 + np.exp(-t))
42
+ )
43
+ ]
44
+
45
+
46
+ # TESTS ================================================================================
47
+
48
+ class TestESDIRK32(unittest.TestCase):
49
+ """
50
+ Test the implementation of the 'ESDIRK32' solver class
51
+ """
52
+
53
+ def test_init(self):
54
+
55
+ #test default initializtion
56
+ solver = ESDIRK32()
57
+
58
+ self.assertTrue(callable(solver.func))
59
+ self.assertEqual(solver.jac, None)
60
+ self.assertEqual(solver.initial_value, 0)
61
+
62
+ self.assertEqual(solver.stage, 0)
63
+ self.assertTrue(solver.is_adaptive)
64
+ self.assertTrue(solver.is_implicit)
65
+ self.assertFalse(solver.is_explicit)
66
+
67
+ #test specific initialization
68
+ solver = ESDIRK32(initial_value=1,
69
+ func=lambda x, u, t: -x,
70
+ jac=lambda x, u, t: -1,
71
+ tolerance_lte=1e-6)
72
+
73
+ self.assertEqual(solver.func(2, 0, 0), -2)
74
+ self.assertEqual(solver.jac(2, 0, 0), -1)
75
+ self.assertEqual(solver.initial_value, 1)
76
+ self.assertEqual(solver.tolerance_lte, 1e-6)
77
+
78
+
79
+ def test_stages(self):
80
+
81
+ solver = ESDIRK32()
82
+
83
+ for i, t in enumerate(solver.stages(0, 1)):
84
+
85
+ #test the stage iterator
86
+ self.assertEqual(t, solver.eval_stages[i])
87
+
88
+
89
+ def test_step(self):
90
+
91
+ solver = ESDIRK32()
92
+
93
+ for i, t in enumerate(solver.stages(0, 1)):
94
+
95
+ #test if stage incrementation works
96
+ self.assertEqual(solver.stage, i)
97
+
98
+ _ = solver.solve(0.0, t, 1) #needed for implicit solvers to get slope
99
+ success, err, scale = solver.step(0.0, t, 1)
100
+
101
+ #test if expected return at intermediate stages
102
+ if i < len(solver.eval_stages)-1:
103
+ self.assertTrue(success)
104
+ self.assertEqual(err, 0.0)
105
+ self.assertEqual(scale, 1.0)
106
+
107
+ #test if expected return at final stage
108
+ self.assertNotEqual(err, 0.0)
109
+ self.assertNotEqual(scale, 1.0)
110
+
111
+
112
+ def test_integrate_fixed(self):
113
+
114
+ #integrate test problem and assess convergence order
115
+
116
+ timesteps = np.logspace(-1, -0.5, 10)
117
+
118
+ for problem in reference_problems:
119
+
120
+ solver = ESDIRK32(problem.x0, problem.func, problem.jac)
121
+
122
+ errors = []
123
+
124
+ for dt in timesteps:
125
+
126
+ solver.reset()
127
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
128
+
129
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
130
+
131
+ #test if errors are monotonically decreasing
132
+ self.assertTrue(np.all(np.diff(errors)>0))
133
+
134
+ #test convergence order, expected 2 or 3
135
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
136
+ self.assertGreater(p, 2.3)
137
+
138
+
139
+ def test_integrate_adaptive(self):
140
+
141
+ #test the error control for each reference problem
142
+
143
+ for problem in reference_problems:
144
+
145
+ solver = ESDIRK32(problem.x0, problem.func, problem.jac, tolerance_lte=1e-6)
146
+
147
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=2.0, dt=1, adaptive=True)
148
+ error = np.linalg.norm(numerical_solution - problem.solution(time))
149
+
150
+ #test if error control was successful (same OOM, since global error)
151
+ self.assertLess(error, solver.tolerance_lte*3)
152
+
153
+
154
+
155
+ # RUN TESTS LOCALLY ====================================================================
156
+
157
+ if __name__ == '__main__':
158
+ unittest.main(verbosity=2)
@@ -0,0 +1,138 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/esdirk4.py'
5
+ ##
6
+ ## Milan Rother 2024
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.solvers.esdirk4 import ESDIRK4
16
+
17
+
18
+ # TEST PROBLEMS ========================================================================
19
+
20
+ class Problem:
21
+ def __init__(self, name, func, jac, x0, solution):
22
+ self.name = name
23
+ self.func = func
24
+ self.jac = jac
25
+ self.x0 = x0
26
+ self.solution = solution
27
+
28
+
29
+ #create some reference problems for testing
30
+ reference_problems = [
31
+ Problem(name="linear_feedback",
32
+ func=lambda x, u, t: -x,
33
+ jac=lambda x, u, t: -1,
34
+ x0=1.0,
35
+ solution=lambda t: np.exp(-t)
36
+ ),
37
+ Problem(name="logistic",
38
+ func=lambda x, u, t: x*(1-x),
39
+ jac=lambda x, u, t: 1-2*x,
40
+ x0=0.5,
41
+ solution=lambda t: 1/(1 + np.exp(-t))
42
+ )
43
+ ]
44
+
45
+
46
+ # TESTS ================================================================================
47
+
48
+ class TestESDIRK4(unittest.TestCase):
49
+ """
50
+ Test the implementation of the 'ESDIRK4' solver class
51
+ """
52
+
53
+ def test_init(self):
54
+
55
+ #test default initializtion
56
+ solver = ESDIRK4()
57
+
58
+ self.assertTrue(callable(solver.func))
59
+ self.assertEqual(solver.jac, None)
60
+ self.assertEqual(solver.initial_value, 0)
61
+
62
+ self.assertEqual(solver.stage, 0)
63
+ self.assertFalse(solver.is_adaptive)
64
+ self.assertTrue(solver.is_implicit)
65
+ self.assertFalse(solver.is_explicit)
66
+
67
+ #test specific initialization
68
+ solver = ESDIRK4(initial_value=1,
69
+ func=lambda x, u, t: -x,
70
+ jac=lambda x, u, t: -1,
71
+ tolerance_lte=1e-6)
72
+
73
+ self.assertEqual(solver.func(2, 0, 0), -2)
74
+ self.assertEqual(solver.jac(2, 0, 0), -1)
75
+ self.assertEqual(solver.initial_value, 1)
76
+ self.assertEqual(solver.tolerance_lte, 1e-6)
77
+
78
+
79
+ def test_stages(self):
80
+
81
+ solver = ESDIRK4()
82
+
83
+ for i, t in enumerate(solver.stages(0, 1)):
84
+
85
+ #test the stage iterator
86
+ self.assertEqual(t, solver.eval_stages[i])
87
+
88
+
89
+ def test_step(self):
90
+
91
+ solver = ESDIRK4()
92
+
93
+ for i, t in enumerate(solver.stages(0, 1)):
94
+
95
+ #test if stage incrementation works
96
+ self.assertEqual(solver.stage, i)
97
+
98
+ _ = solver.solve(0.0, t, 1) #needed for implicit solvers to get slope
99
+ success, err, scale = solver.step(0.0, t, 1)
100
+
101
+ #test if expected return at intermediate stages
102
+ self.assertTrue(success)
103
+ self.assertEqual(err, 0.0)
104
+ self.assertEqual(scale, 1.0)
105
+
106
+
107
+ def test_integrate_fixed(self):
108
+
109
+ #integrate test problem and assess convergence order
110
+
111
+ timesteps = np.logspace(-0.5, -0.1, 10)
112
+
113
+ for problem in reference_problems:
114
+
115
+ solver = ESDIRK4(problem.x0, problem.func, problem.jac)
116
+
117
+ errors = []
118
+
119
+ for dt in timesteps:
120
+
121
+ solver.reset()
122
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
123
+
124
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
125
+
126
+ #test if errors are monotonically decreasing
127
+ self.assertTrue(np.all(np.diff(errors)>0))
128
+
129
+ #test convergence order, expected 3 or 4
130
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
131
+ self.assertEqual(round(p), 4)
132
+
133
+
134
+
135
+ # RUN TESTS LOCALLY ====================================================================
136
+
137
+ if __name__ == '__main__':
138
+ unittest.main(verbosity=2)