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,158 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/esdirk43.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.esdirk43 import ESDIRK43
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 TestESDIRK43(unittest.TestCase):
50
+ """
51
+ Test the implementation of the 'ESDIRK43' solver class
52
+ """
53
+
54
+ def test_init(self):
55
+
56
+ #test default initializtion
57
+ solver = ESDIRK43()
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.assertTrue(solver.is_adaptive)
65
+ self.assertTrue(solver.is_implicit)
66
+ self.assertFalse(solver.is_explicit)
67
+
68
+ #test specific initialization
69
+ solver = ESDIRK43(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 = ESDIRK43()
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 = ESDIRK43()
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
+ if i < len(solver.eval_stages)-1:
104
+ self.assertTrue(success)
105
+ self.assertEqual(err, 0.0)
106
+ self.assertEqual(scale, 1.0)
107
+
108
+ #test if expected return at final stage
109
+ self.assertNotEqual(err, 0.0)
110
+ self.assertNotEqual(scale, 1.0)
111
+
112
+
113
+ def test_integrate_fixed(self):
114
+
115
+ #integrate test problem and assess convergence order
116
+
117
+ timesteps = np.logspace(-0.4, 0, 10)
118
+
119
+ for problem in reference_problems:
120
+
121
+ solver = ESDIRK43(problem.x0, problem.func, problem.jac)
122
+
123
+ errors = []
124
+
125
+ for dt in timesteps:
126
+
127
+ solver.reset()
128
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
129
+
130
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
131
+
132
+ #test if errors are monotonically decreasing
133
+ self.assertTrue(np.all(np.diff(errors)>0))
134
+
135
+ #test convergence order, expected 3 or 4
136
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
137
+ self.assertEqual(round(p), 4)
138
+
139
+
140
+ def test_integrate_adaptive(self):
141
+
142
+ #test the error control for each reference problem
143
+
144
+ for problem in reference_problems:
145
+
146
+ solver = ESDIRK43(problem.x0, problem.func, problem.jac, tolerance_lte=1e-6)
147
+
148
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=2.0, dt=1, adaptive=True)
149
+ error = np.linalg.norm(numerical_solution - problem.solution(time))
150
+
151
+ #test if error control was successful (same OOM, since global error)
152
+ self.assertLess(error, solver.tolerance_lte*3)
153
+
154
+
155
+ # RUN TESTS LOCALLY ====================================================================
156
+
157
+ if __name__ == '__main__':
158
+ unittest.main(verbosity=2)
@@ -0,0 +1,160 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/esdirk54.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.esdirk54 import ESDIRK54
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 TestESDIRK54(unittest.TestCase):
50
+ """
51
+ Test the implementation of the 'ESDIRK54' solver class
52
+ """
53
+
54
+ def test_init(self):
55
+
56
+ #test default initializtion
57
+ solver = ESDIRK54()
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.assertTrue(solver.is_adaptive)
65
+ self.assertTrue(solver.is_implicit)
66
+ self.assertFalse(solver.is_explicit)
67
+
68
+ #test specific initialization
69
+ solver = ESDIRK54(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 = ESDIRK54()
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 = ESDIRK54()
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
+ if i < len(solver.eval_stages)-1:
104
+ self.assertTrue(success)
105
+ self.assertEqual(err, 0.0)
106
+ self.assertEqual(scale, 1.0)
107
+
108
+ #test if expected return at final stage
109
+ self.assertNotEqual(err, 0.0)
110
+ self.assertNotEqual(scale, 1.0)
111
+
112
+
113
+ def test_integrate_fixed(self):
114
+
115
+ #integrate test problem and assess convergence order
116
+
117
+ timesteps = np.logspace(-0.4, 0, 10)
118
+
119
+ for problem in reference_problems:
120
+
121
+ solver = ESDIRK54(problem.x0, problem.func, problem.jac)
122
+
123
+ errors = []
124
+
125
+ for dt in timesteps:
126
+
127
+ solver.reset()
128
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=3.0, dt=dt, adaptive=False)
129
+
130
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
131
+
132
+ #test if errors are monotonically decreasing
133
+ self.assertTrue(np.all(np.diff(errors)>0))
134
+
135
+ #test convergence order, expected 4 or 5
136
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
137
+ self.assertGreater(p, 4)
138
+
139
+
140
+ def test_integrate_adaptive(self):
141
+
142
+ #test the error control for each reference problem
143
+
144
+ for problem in reference_problems:
145
+
146
+ solver = ESDIRK54(problem.x0, problem.func, problem.jac, tolerance_lte=1e-6)
147
+
148
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=1.0, dt=1, adaptive=True)
149
+ error = np.linalg.norm(numerical_solution - problem.solution(time))
150
+
151
+ #test if error control was successful
152
+ self.assertLess(error, solver.tolerance_lte)
153
+
154
+
155
+
156
+
157
+ # RUN TESTS LOCALLY ====================================================================
158
+
159
+ if __name__ == '__main__':
160
+ unittest.main(verbosity=2)
@@ -0,0 +1,157 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/esdirk85.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.esdirk85 import ESDIRK85
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 TestESDIRK85(unittest.TestCase):
49
+ """
50
+ Test the implementation of the 'ESDIRK85' solver class
51
+ """
52
+
53
+ def test_init(self):
54
+
55
+ #test default initializtion
56
+ solver = ESDIRK85()
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 = ESDIRK85(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 = ESDIRK85()
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 = ESDIRK85()
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(-0.4, 0, 10)
117
+
118
+ for problem in reference_problems:
119
+
120
+ solver = ESDIRK85(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 7 or 8
135
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
136
+ self.assertGreaterEqual(round(p), 7)
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 = ESDIRK85(problem.x0, problem.func, problem.jac, tolerance_lte=1e-6)
146
+
147
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=1.0, dt=1, adaptive=True)
148
+ error = np.linalg.norm(numerical_solution - problem.solution(time))
149
+
150
+ #test if error control was successful
151
+ self.assertLess(error, solver.tolerance_lte)
152
+
153
+
154
+ # RUN TESTS LOCALLY ====================================================================
155
+
156
+ if __name__ == '__main__':
157
+ unittest.main(verbosity=2)
@@ -0,0 +1,223 @@
1
+ ########################################################################################
2
+ ##
3
+ ## TESTS FOR
4
+ ## 'solvers/euler.py'
5
+ ##
6
+ ## Milan Rother 2023/24
7
+ ##
8
+ ########################################################################################
9
+
10
+ # IMPORTS ==============================================================================
11
+
12
+ import unittest
13
+ import numpy as np
14
+
15
+ from pathsim.solvers.euler import EUF, EUB
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 TestEUF(unittest.TestCase):
50
+ """
51
+ Test the implementation of the 'EUF' solver class
52
+ """
53
+
54
+ def test_init(self):
55
+
56
+ #test default initializtion
57
+ solver = EUF()
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_explicit)
66
+ self.assertFalse(solver.is_implicit)
67
+
68
+ #test specific initialization
69
+ solver = EUF(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 = EUF()
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 = EUF()
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
+ 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.4, 0, 20)
112
+
113
+ for problem in reference_problems:
114
+
115
+ solver = EUF(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 1
130
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
131
+ self.assertEqual(round(p), 1)
132
+
133
+
134
+
135
+ class TestEUB(unittest.TestCase):
136
+ """
137
+ Test the implementation of the 'EUB' solver class
138
+ """
139
+
140
+ def test_init(self):
141
+
142
+ #test default initializtion
143
+ solver = EUB()
144
+
145
+ self.assertTrue(callable(solver.func))
146
+ self.assertEqual(solver.jac, None)
147
+ self.assertEqual(solver.initial_value, 0)
148
+
149
+ self.assertEqual(solver.stage, 0)
150
+ self.assertFalse(solver.is_adaptive)
151
+ self.assertTrue(solver.is_implicit)
152
+ self.assertFalse(solver.is_explicit)
153
+
154
+ #test specific initialization
155
+ solver = EUB(initial_value=1,
156
+ func=lambda x, u, t: -x,
157
+ jac=lambda x, u, t: -1,
158
+ tolerance_lte=1e-6)
159
+
160
+ self.assertEqual(solver.func(2, 0, 0), -2)
161
+ self.assertEqual(solver.jac(2, 0, 0), -1)
162
+ self.assertEqual(solver.initial_value, 1)
163
+ self.assertEqual(solver.tolerance_lte, 1e-6)
164
+
165
+
166
+ def test_stages(self):
167
+
168
+ solver = EUB()
169
+
170
+ for i, t in enumerate(solver.stages(0, 1)):
171
+
172
+ #test the stage iterator
173
+ self.assertEqual(t, solver.eval_stages[i])
174
+
175
+
176
+ def test_step(self):
177
+
178
+ solver = EUB()
179
+
180
+ for i, t in enumerate(solver.stages(0, 1)):
181
+
182
+ #test if stage incrementation works
183
+ self.assertEqual(solver.stage, i)
184
+
185
+ success, err, scale = solver.step(0.0, t, 1)
186
+
187
+ #test if expected return at intermediate stages
188
+ self.assertTrue(success)
189
+ self.assertEqual(err, 0.0)
190
+ self.assertEqual(scale, 1.0)
191
+
192
+
193
+ def test_integrate_fixed(self):
194
+
195
+ #integrate test problem and assess convergence order
196
+
197
+ timesteps = np.logspace(-2, -1, 10)
198
+
199
+ for problem in reference_problems:
200
+
201
+ solver = EUB(problem.x0, problem.func, problem.jac)
202
+
203
+ errors = []
204
+
205
+ for dt in timesteps:
206
+
207
+ solver.reset()
208
+ time, numerical_solution = solver.integrate(time_start=0.0, time_end=1.0, dt=dt, adaptive=False)
209
+
210
+ errors.append(np.linalg.norm(numerical_solution - problem.solution(time)))
211
+
212
+ #test if errors are monotonically decreasing
213
+ self.assertTrue(np.all(np.diff(errors)>0))
214
+
215
+ #test convergence order, expected 1
216
+ p, _ = np.polyfit(np.log10(timesteps), np.log10(errors), deg=1)
217
+ self.assertGreater(p, 0.5)
218
+
219
+
220
+ # RUN TESTS LOCALLY ====================================================================
221
+
222
+ if __name__ == '__main__':
223
+ unittest.main(verbosity=2)