myokit 1.33.9__py3-none-any.whl → 1.35.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 (229) hide show
  1. myokit/__init__.py +9 -36
  2. myokit/__main__.py +76 -142
  3. myokit/_aux.py +62 -16
  4. myokit/_bin/example.mmt +1 -2
  5. myokit/_bin/install-win/menu.json +7 -7
  6. myokit/_config.py +22 -31
  7. myokit/_datablock.py +30 -74
  8. myokit/_datalog.py +49 -72
  9. myokit/_err.py +25 -24
  10. myokit/_expressions.py +50 -68
  11. myokit/_io.py +15 -27
  12. myokit/_model_api.py +453 -249
  13. myokit/_myokit_version.py +1 -5
  14. myokit/_parsing.py +38 -44
  15. myokit/_progress.py +5 -8
  16. myokit/_protocol.py +99 -9
  17. myokit/_sim/__init__.py +7 -24
  18. myokit/_sim/cable.c +6 -8
  19. myokit/_sim/cable.py +6 -8
  20. myokit/_sim/cmodel.h +125 -70
  21. myokit/_sim/cmodel.py +12 -14
  22. myokit/_sim/compiler.py +1 -4
  23. myokit/_sim/cvodessim.c +196 -118
  24. myokit/_sim/cvodessim.py +130 -103
  25. myokit/_sim/differential.hpp +4 -4
  26. myokit/_sim/fiber_tissue.c +4 -8
  27. myokit/_sim/fiber_tissue.py +11 -13
  28. myokit/_sim/jacobian.cpp +2 -2
  29. myokit/_sim/jacobian.py +11 -8
  30. myokit/_sim/mcl.h +53 -55
  31. myokit/_sim/opencl.py +21 -27
  32. myokit/_sim/openclsim.c +3 -7
  33. myokit/_sim/openclsim.cl +3 -3
  34. myokit/_sim/openclsim.py +49 -40
  35. myokit/_sim/pacing.h +36 -16
  36. myokit/_sim/rhs.c +6 -13
  37. myokit/_sim/rhs.py +5 -14
  38. myokit/_sim/sundials.py +1 -4
  39. myokit/_system.py +10 -16
  40. myokit/_unit.py +4 -13
  41. myokit/float.py +0 -3
  42. myokit/formats/__init__.py +8 -10
  43. myokit/formats/ansic/__init__.py +0 -3
  44. myokit/formats/ansic/_ewriter.py +2 -4
  45. myokit/formats/ansic/_exporter.py +1 -4
  46. myokit/formats/ansic/template/cable.c +4 -4
  47. myokit/formats/ansic/template/euler.c +5 -5
  48. myokit/formats/ansic/template/sim.c +6 -6
  49. myokit/formats/axon/__init__.py +1 -3
  50. myokit/formats/axon/_abf.py +12 -17
  51. myokit/formats/axon/_atf.py +5 -6
  52. myokit/formats/axon/_importer.py +0 -3
  53. myokit/formats/cellml/__init__.py +0 -3
  54. myokit/formats/cellml/_ewriter.py +3 -6
  55. myokit/formats/cellml/_exporter.py +3 -6
  56. myokit/formats/cellml/_importer.py +1 -4
  57. myokit/formats/cellml/v1/__init__.py +0 -4
  58. myokit/formats/cellml/v1/_api.py +8 -11
  59. myokit/formats/cellml/v1/_parser.py +2 -5
  60. myokit/formats/cellml/v1/_writer.py +2 -11
  61. myokit/formats/cellml/v2/__init__.py +0 -3
  62. myokit/formats/cellml/v2/_api.py +8 -17
  63. myokit/formats/cellml/v2/_parser.py +2 -5
  64. myokit/formats/cellml/v2/_writer.py +1 -4
  65. myokit/formats/channelml/__init__.py +0 -3
  66. myokit/formats/channelml/_importer.py +11 -21
  67. myokit/formats/cpp/__init__.py +1 -3
  68. myokit/formats/cpp/_ewriter.py +0 -3
  69. myokit/formats/cuda/__init__.py +0 -3
  70. myokit/formats/cuda/_ewriter.py +2 -4
  71. myokit/formats/cuda/_exporter.py +0 -3
  72. myokit/formats/cuda/template/kernel.cu +8 -5
  73. myokit/formats/easyml/__init__.py +0 -3
  74. myokit/formats/easyml/_ewriter.py +9 -11
  75. myokit/formats/easyml/_exporter.py +2 -5
  76. myokit/formats/html/__init__.py +0 -3
  77. myokit/formats/html/_exporter.py +0 -3
  78. myokit/formats/html/_flatten.py +5 -21
  79. myokit/formats/latex/__init__.py +0 -3
  80. myokit/formats/latex/_ewriter.py +1 -4
  81. myokit/formats/latex/_exporter.py +4 -6
  82. myokit/formats/mathml/__init__.py +0 -3
  83. myokit/formats/mathml/_ewriter.py +2 -11
  84. myokit/formats/mathml/_parser.py +4 -6
  85. myokit/formats/matlab/__init__.py +0 -3
  86. myokit/formats/matlab/_ewriter.py +1 -4
  87. myokit/formats/matlab/_exporter.py +2 -5
  88. myokit/formats/matlab/template/main.m +3 -2
  89. myokit/formats/opencl/__init__.py +0 -3
  90. myokit/formats/opencl/_ewriter.py +2 -4
  91. myokit/formats/opencl/_exporter.py +2 -5
  92. myokit/formats/opencl/template/cable.c +10 -10
  93. myokit/formats/opencl/template/kernel.cl +1 -1
  94. myokit/formats/opencl/template/minilog.py +1 -1
  95. myokit/formats/python/__init__.py +0 -3
  96. myokit/formats/python/_ewriter.py +2 -5
  97. myokit/formats/python/_exporter.py +0 -3
  98. myokit/formats/python/template/sim.py +14 -14
  99. myokit/formats/sbml/__init__.py +0 -3
  100. myokit/formats/sbml/_api.py +50 -44
  101. myokit/formats/sbml/_importer.py +1 -4
  102. myokit/formats/sbml/_parser.py +2 -5
  103. myokit/formats/stan/__init__.py +0 -3
  104. myokit/formats/stan/_ewriter.py +2 -4
  105. myokit/formats/stan/_exporter.py +2 -5
  106. myokit/formats/stan/template/cell.stan +3 -3
  107. myokit/formats/sympy/__init__.py +0 -3
  108. myokit/formats/sympy/_ereader.py +1 -4
  109. myokit/formats/sympy/_ewriter.py +2 -5
  110. myokit/formats/wcp/__init__.py +0 -3
  111. myokit/formats/wcp/_wcp.py +2 -8
  112. myokit/formats/xml/__init__.py +0 -3
  113. myokit/formats/xml/_exporter.py +0 -3
  114. myokit/formats/xml/_split.py +0 -3
  115. myokit/gui/__init__.py +80 -246
  116. myokit/gui/datablock_viewer.py +103 -86
  117. myokit/gui/datalog_viewer.py +214 -66
  118. myokit/gui/explorer.py +15 -21
  119. myokit/gui/ide.py +171 -144
  120. myokit/gui/progress.py +9 -9
  121. myokit/gui/source.py +406 -375
  122. myokit/gui/vargrapher.py +2 -12
  123. myokit/lib/deps.py +12 -13
  124. myokit/lib/guess.py +3 -4
  125. myokit/lib/hh.py +20 -18
  126. myokit/lib/markov.py +21 -20
  127. myokit/lib/multi.py +1 -3
  128. myokit/lib/plots.py +20 -9
  129. myokit/pacing.py +0 -3
  130. myokit/pype.py +7 -18
  131. myokit/tests/__init__.py +3 -6
  132. myokit/tests/ansic_event_based_pacing.py +1 -4
  133. myokit/tests/ansic_fixed_form_pacing.py +3 -6
  134. myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
  135. myokit/tests/data/clancy-1999-fitting.mmt +1 -0
  136. myokit/tests/test_aux.py +13 -28
  137. myokit/tests/test_cellml_v1_api.py +4 -19
  138. myokit/tests/test_cellml_v1_parser.py +0 -15
  139. myokit/tests/test_cellml_v1_writer.py +0 -9
  140. myokit/tests/test_cellml_v2_api.py +4 -19
  141. myokit/tests/test_cellml_v2_parser.py +0 -15
  142. myokit/tests/test_cellml_v2_writer.py +0 -9
  143. myokit/tests/test_cmodel.py +16 -22
  144. myokit/tests/test_compiler_detection.py +1 -11
  145. myokit/tests/test_component.py +108 -56
  146. myokit/tests/test_config.py +34 -67
  147. myokit/tests/test_datablock.py +1 -9
  148. myokit/tests/test_datalog.py +19 -24
  149. myokit/tests/test_dependency_checking.py +8 -23
  150. myokit/tests/test_expressions.py +0 -9
  151. myokit/tests/test_float.py +1 -5
  152. myokit/tests/test_formats.py +0 -9
  153. myokit/tests/test_formats_axon.py +1 -9
  154. myokit/tests/test_formats_cellml.py +0 -15
  155. myokit/tests/test_formats_channelml.py +0 -15
  156. myokit/tests/test_formats_easyml.py +0 -14
  157. myokit/tests/test_formats_exporters.py +1 -16
  158. myokit/tests/test_formats_expression_writers.py +1 -17
  159. myokit/tests/test_formats_html.py +0 -3
  160. myokit/tests/test_formats_importers.py +1 -16
  161. myokit/tests/test_formats_mathml_content.py +0 -9
  162. myokit/tests/test_formats_mathml_presentation.py +0 -9
  163. myokit/tests/test_formats_opencl.py +0 -10
  164. myokit/tests/test_formats_sbml.py +0 -15
  165. myokit/tests/test_formats_sympy.py +0 -9
  166. myokit/tests/test_formats_wcp.py +1 -3
  167. myokit/tests/test_io.py +27 -27
  168. myokit/tests/test_jacobian_calculator.py +6 -14
  169. myokit/tests/test_jacobian_tracer.py +0 -9
  170. myokit/tests/test_lib_deps.py +0 -9
  171. myokit/tests/test_lib_guess.py +0 -9
  172. myokit/tests/test_lib_hh.py +18 -12
  173. myokit/tests/test_lib_markov.py +21 -13
  174. myokit/tests/test_lib_multi.py +0 -9
  175. myokit/tests/test_lib_plots.py +13 -8
  176. myokit/tests/test_meta.py +0 -3
  177. myokit/tests/test_model.py +390 -96
  178. myokit/tests/test_model_building.py +44 -96
  179. myokit/tests/test_opencl_info.py +5 -14
  180. myokit/tests/test_pacing_factory.py +0 -3
  181. myokit/tests/test_pacing_system_c.py +1 -23
  182. myokit/tests/test_pacing_system_py.py +0 -9
  183. myokit/tests/test_parsing.py +139 -56
  184. myokit/tests/test_progress_reporters.py +0 -3
  185. myokit/tests/test_protocol.py +0 -9
  186. myokit/tests/test_protocol_floating_point.py +1 -10
  187. myokit/tests/test_protocol_time_series.py +82 -0
  188. myokit/tests/test_pype.py +0 -9
  189. myokit/tests/test_quantity.py +0 -9
  190. myokit/tests/test_rhs_benchmarker.py +1 -9
  191. myokit/tests/test_sbml_api.py +27 -42
  192. myokit/tests/test_sbml_parser.py +4 -19
  193. myokit/tests/test_simulation_1d.py +45 -25
  194. myokit/tests/test_simulation_cvodes.py +321 -55
  195. myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
  196. myokit/tests/test_simulation_fiber_tissue.py +39 -12
  197. myokit/tests/test_simulation_log_interval.py +1 -431
  198. myokit/tests/test_simulation_opencl.py +69 -48
  199. myokit/tests/test_simulation_opencl_log_interval.py +1 -3
  200. myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
  201. myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
  202. myokit/tests/test_system_info.py +1 -11
  203. myokit/tests/test_tools.py +0 -9
  204. myokit/tests/test_unit.py +1 -10
  205. myokit/tests/test_user_functions.py +0 -10
  206. myokit/tests/test_variable.py +231 -27
  207. myokit/tools.py +5 -21
  208. myokit/units.py +5 -3
  209. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
  210. myokit-1.35.0.dist-info/RECORD +391 -0
  211. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
  212. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
  213. myokit/_exec_new.py +0 -15
  214. myokit/_exec_old.py +0 -15
  215. myokit/_sim/cvodesim.c +0 -1551
  216. myokit/_sim/cvodesim.py +0 -674
  217. myokit/_sim/icsim.cpp +0 -563
  218. myokit/_sim/icsim.py +0 -363
  219. myokit/_sim/psim.cpp +0 -656
  220. myokit/_sim/psim.py +0 -493
  221. myokit/lib/common.py +0 -1094
  222. myokit/tests/test_lib_common.py +0 -130
  223. myokit/tests/test_simulation_cvode.py +0 -612
  224. myokit/tests/test_simulation_ic.py +0 -108
  225. myokit/tests/test_simulation_p.py +0 -223
  226. myokit-1.33.9.dist-info/RECORD +0 -403
  227. /myokit/formats/opencl/template/{test → test.sh} +0 -0
  228. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
  229. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
@@ -1,612 +0,0 @@
1
- #!/usr/bin/env python3
2
- #
3
- # Tests the CVODE simulation class.
4
- #
5
- # This file is part of Myokit.
6
- # See http://myokit.org for copyright, sharing, and licensing details.
7
- #
8
- from __future__ import absolute_import, division
9
- from __future__ import print_function, unicode_literals
10
-
11
- import os
12
- import pickle
13
- import platform
14
- import re
15
- import sys
16
- import unittest
17
-
18
- import numpy as np
19
-
20
- import myokit
21
-
22
- from myokit.tests import DIR_DATA, CancellingReporter, WarningCollector
23
-
24
- # Unit testing in Python 2 and 3
25
- try:
26
- unittest.TestCase.assertRaisesRegex
27
- except AttributeError:
28
- unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
29
-
30
-
31
- @unittest.skipIf(platform.system() != 'Linux', 'Legacy CVODE tests')
32
- class LegacySimulationTest(unittest.TestCase):
33
- """
34
- Tests the Legacy CVODE simulation class.
35
- """
36
-
37
- @classmethod
38
- def setUpClass(cls):
39
- # Test simulation creation.
40
-
41
- m, p, x = myokit.load(os.path.join(DIR_DATA, 'lr-1991.mmt'))
42
- cls.model = m
43
- cls.protocol = p
44
- cls.sim = myokit.LegacySimulation(cls.model, cls.protocol)
45
-
46
- def test_pre(self):
47
- # Test pre-pacing.
48
-
49
- self.sim.reset()
50
- self.sim.pre(200)
51
-
52
- def test_simple(self):
53
- # Test simple run.
54
-
55
- self.sim.reset()
56
- self.assertEqual(self.sim.time(), 0)
57
- self.sim.pre(5)
58
- self.assertEqual(self.sim.time(), 0)
59
- d = self.sim.run(5)
60
- self.assertEqual(self.sim.time(), 5)
61
- self.sim.set_time(0)
62
- self.assertEqual(self.sim.time(), 0)
63
- self.assertEqual(type(d), myokit.DataLog)
64
- self.assertIn('engine.time', d)
65
- n = len(d['engine.time'])
66
- for k, v in d.items():
67
- self.assertEqual(n, len(v))
68
-
69
- # Can't do negative times
70
- self.assertRaisesRegex(ValueError, 'negative', self.sim.run, -1)
71
-
72
- # Negative log interval is set to zero
73
- self.sim.reset()
74
- d1 = self.sim.run(5)
75
- self.sim.reset()
76
- d2 = self.sim.run(5, log_interval=-5)
77
- self.assertEqual(d1.time(), d2.time())
78
-
79
- def test_no_protocol(self):
80
- # Test running without a protocol.
81
-
82
- self.sim.reset()
83
- self.sim.pre(50)
84
- self.sim.set_protocol(None)
85
- d = self.sim.run(50).npview()
86
-
87
- # Check if pace was set to zero (see prop 651 / technical docs).
88
- self.assertTrue(np.all(d['engine.pace'] == 0.0))
89
-
90
- def test_fixed_form_protocol(self):
91
- # Test running with a fixed form protocol.
92
-
93
- n = 10
94
- time = list(range(n))
95
- pace = [0] * n
96
- pace[2:4] = [0.5, 0.5]
97
-
98
- self.sim.set_fixed_form_protocol(time, pace)
99
- self.sim.reset()
100
- d = self.sim.run(n, log_interval=1)
101
- self.assertEqual(list(d.time()), time)
102
- self.assertEqual(list(d['engine.pace']), pace)
103
-
104
- # Unset
105
- self.sim.set_fixed_form_protocol(None)
106
- self.sim.reset()
107
- d = self.sim.run(n, log_interval=1)
108
- self.assertEqual(list(d['engine.pace']), [0] * n)
109
-
110
- # Reset
111
- self.sim.set_fixed_form_protocol(time, pace)
112
- self.sim.reset()
113
- d = self.sim.run(n, log_interval=1)
114
- self.assertEqual(list(d.time()), time)
115
- self.assertEqual(list(d['engine.pace']), pace)
116
-
117
- # Unset, replace with original protocol
118
- self.sim.set_protocol(self.protocol)
119
- self.sim.reset()
120
- d = self.sim.run(n, log_interval=1)
121
- self.assertNotEqual(list(d['engine.pace']), pace)
122
- self.assertNotEqual(list(d['engine.pace']), [0] * n)
123
-
124
- # Invalid protocols
125
- self.assertRaisesRegex(
126
- ValueError, 'no times', self.sim.set_fixed_form_protocol,
127
- values=pace)
128
- self.assertRaisesRegex(
129
- ValueError, 'no values', self.sim.set_fixed_form_protocol,
130
- times=time)
131
- self.assertRaisesRegex(
132
- ValueError, 'same size', self.sim.set_fixed_form_protocol,
133
- time, pace[:-1])
134
-
135
- def test_in_parts(self):
136
- # Test running the simulation in parts.
137
-
138
- self.sim.reset()
139
- # New logs should start with first state, finish with final
140
- d = self.sim.run(150)
141
- self.assertEqual(d['engine.time'][0], 0.0)
142
- self.assertEqual(d['engine.time'][-1], 150.0)
143
- # Next part should continue at 150, leave where last left off
144
- e = self.sim.run(50)
145
- self.assertEqual(d['engine.time'][-1], e['engine.time'][0])
146
- self.assertEqual(d['membrane.V'][-1], e['membrane.V'][0])
147
- # Re-used logs shouldn't re-log their first state
148
- n = len(e['engine.time'])
149
- e = self.sim.run(50, log=e)
150
- self.assertNotEqual(e['engine.time'][n - 1], e['engine.time'][n])
151
- self.assertGreater(e['engine.time'][n], e['engine.time'][n - 1])
152
-
153
- def test_pacing_values_at_event_transitions(self):
154
- # Tests the value of the pacing signal at event transitions
155
-
156
- # Create a simple model
157
- m = myokit.Model()
158
- c = m.add_component('c')
159
- t = c.add_variable('t')
160
- t.set_rhs(0)
161
- t.set_binding('time')
162
- v = c.add_variable('v')
163
- v.set_rhs('0')
164
- v.set_binding('pace')
165
- x = c.add_variable('x')
166
- x.set_rhs(0.1)
167
- x.promote(0)
168
-
169
- # Create step protocol
170
- p = myokit.Protocol()
171
- p.schedule(0, 0, 2)
172
- p.schedule(1, 2, 2)
173
- p.schedule(2, 4, 4)
174
- p.schedule(3, 8, 2)
175
-
176
- # Simulate with dynamic logging
177
- s = myokit.LegacySimulation(m, p)
178
- d = s.run(p.characteristic_time())
179
- time = list(d.time())
180
- value = list(d['c.v'])
181
-
182
- if False:
183
- for i, t in enumerate(d.time()):
184
- t = str(np.round(t, 5))
185
- print(t + ' ' * (10 - len(t)) + str(d['c.v'][i]))
186
-
187
- # Values should be
188
- # t 0 1 2 3 4 5 6 7 8 9 10
189
- # p 0 0 1 1 2 2 2 2 3 3 0
190
- self.assertEqual(value[time.index(0.0)], 0)
191
- self.assertEqual(value[time.index(0.0) + 1], 0)
192
- self.assertEqual(value[time.index(2.0) - 1], 0)
193
- self.assertEqual(value[time.index(2.0)], 1)
194
- self.assertEqual(value[time.index(2.0) + 1], 1)
195
- self.assertEqual(value[time.index(4.0) - 1], 1)
196
- self.assertEqual(value[time.index(4.0)], 2)
197
- self.assertEqual(value[time.index(4.0) + 1], 2)
198
- self.assertEqual(value[time.index(8.0) - 1], 2)
199
- self.assertEqual(value[time.index(8.0)], 3)
200
- self.assertEqual(value[time.index(8.0) + 1], 3)
201
- self.assertEqual(value[time.index(10.0) - 1], 3)
202
- self.assertEqual(value[time.index(10.0)], 0)
203
-
204
- # Simulate with fixed logging
205
- s.reset()
206
- d = s.run(p.characteristic_time() + 1, log_times=d.time())
207
- time2 = list(d.time())
208
- value2 = list(d['c.v'])
209
- self.assertEqual(time, time2)
210
- self.assertEqual(value, value2)
211
-
212
- def test_progress_reporter(self):
213
- # Test running with a progress reporter.
214
-
215
- # Test if it works
216
- sim = myokit.LegacySimulation(self.model, self.protocol)
217
- with myokit.tools.capture() as c:
218
- sim.run(110, progress=myokit.ProgressPrinter())
219
- c = c.text().splitlines()
220
- self.assertEqual(len(c), 2)
221
- p = re.compile(re.escape('[0.0 minutes] 1.9 % done, estimated ') +
222
- '[0-9]+' + re.escape(' seconds remaining'))
223
- self.assertIsNotNone(p.match(c[0]))
224
- p = re.compile(re.escape('[0.0 minutes] 100.0 % done, estimated ') +
225
- '[0-9]+' + re.escape(' seconds remaining'))
226
- self.assertIsNotNone(p.match(c[1]))
227
-
228
- # Not a progress reporter
229
- self.assertRaisesRegex(
230
- ValueError, 'ProgressReporter', self.sim.run, 5, progress=12)
231
-
232
- # Cancel from reporter
233
- self.assertRaises(
234
- myokit.SimulationCancelledError, self.sim.run, 1,
235
- progress=CancellingReporter(0))
236
-
237
- def test_apd_tracking(self):
238
- # Test the APD calculation method.
239
-
240
- # More testing is done in test_datalog.py!
241
-
242
- # Apd var is not a state
243
- v = self.model.get('ina.INa')
244
- self.assertRaisesRegex(
245
- ValueError, 'must be a state', myokit.LegacySimulation, self.model,
246
- self.protocol, apd_var=v)
247
-
248
- # Set a valid apd variable
249
- v = self.model.get('ik.x')
250
- sim = myokit.LegacySimulation(
251
- self.model, self.protocol, apd_var=v)
252
- sim.run(1, apd_threshold=12)
253
-
254
- # No apd var given, but threshold provided
255
- self.assertRaisesRegex(
256
- ValueError, 'without apd_var', self.sim.run, 1, apd_threshold=12)
257
-
258
- def test_last_state(self):
259
- # Returns the last state before an error, or None.
260
-
261
- m = self.model.clone()
262
- istim = m.get('membrane.i_stim')
263
- istim.set_rhs('engine.pace / stim_amplitude')
264
- s = myokit.LegacySimulation(m, self.protocol)
265
- self.assertIsNone(s.last_state())
266
- s.run(1)
267
- self.assertIsNone(s.last_state())
268
- s.set_constant('membrane.i_stim.stim_amplitude', 0)
269
- s.reset()
270
- self.assertRaisesRegex(myokit.SimulationError, "at t = 0", s.run, 5)
271
- self.assertEqual(len(s.last_state()), len(s.state()))
272
- self.assertEqual(s.last_state(), s.state())
273
-
274
- def test_last_evaluations_and_steps(self):
275
- # Test :meth:`LegacySimulation.last_number_of_evaluations()` and
276
- # :meth:`LegacySimulation.last_number_of_steps()`
277
-
278
- s = myokit.LegacySimulation(self.model, self.protocol)
279
- self.assertEqual(s.last_number_of_evaluations(), 0)
280
- self.assertEqual(s.last_number_of_steps(), 0)
281
- s.run(1)
282
- self.assertTrue(s.last_number_of_evaluations() > 0)
283
- self.assertTrue(s.last_number_of_steps() > 0)
284
- self.assertNotEqual(
285
- s.last_number_of_evaluations(), s.last_number_of_steps())
286
-
287
- def test_eval_derivatives(self):
288
- # Test :meth:`LegacySimulation.eval_derivatives()`.
289
-
290
- self.sim.reset()
291
- s1 = self.sim.state()
292
- d1 = self.sim.eval_derivatives()
293
- self.sim.run(1)
294
- d2 = self.sim.eval_derivatives()
295
- self.assertNotEqual(d1, d2)
296
- self.assertEqual(d1, self.sim.eval_derivatives(s1))
297
- self.sim.set_state(s1)
298
- self.assertEqual(d1, self.sim.eval_derivatives())
299
-
300
- def test_set_tolerance(self):
301
- # Test :meth:`LegacySimulation.set_tolerance()`.
302
-
303
- self.assertRaisesRegex(
304
- ValueError, 'Absolute', self.sim.set_tolerance, abs_tol=0)
305
- self.assertRaisesRegex(
306
- ValueError, 'Relative', self.sim.set_tolerance, rel_tol=0)
307
- self.sim.set_tolerance(1e-6, 1e-4)
308
-
309
- def test_set_step_size(self):
310
- # Test :meth:`LegacySimulation.set_min_step_size()` and
311
- # :meth:`LegacySimulation.set_max_step_size()`.
312
-
313
- # Minimum: set, unset, allow negative value to unset
314
- self.sim.set_min_step_size(0.1)
315
- self.sim.set_min_step_size(None)
316
- self.sim.set_min_step_size(-1)
317
-
318
- # Same for max
319
- self.sim.set_max_step_size(0.1)
320
- self.sim.set_max_step_size(None)
321
- self.sim.set_max_step_size(-1)
322
-
323
- def test_set_state(self):
324
- # Test :meth:`LegacySimulation.set_state()` and
325
- # :meth:`LegacySimulation.set_default_state()`.
326
-
327
- # Get state and default state, both different from current
328
- state = self.sim.state()
329
- state[0] += 1
330
- default_state = self.sim.default_state()
331
- default_state[1] += 1
332
- if state == default_state:
333
- default_state[0] += 2
334
-
335
- self.assertNotEqual(self.sim.state(), state)
336
- self.assertNotEqual(self.sim.default_state(), default_state)
337
-
338
- self.sim.set_state(state)
339
- self.sim.set_default_state(default_state)
340
-
341
- self.assertEqual(self.sim.state(), state)
342
- self.assertEqual(self.sim.default_state(), default_state)
343
-
344
- def test_set_constant(self):
345
- # Test :meth:`LegacySimulation.set_constant()`.
346
-
347
- # Literal
348
- v = self.model.get('cell.Na_i')
349
- self.sim.set_constant(v, 11)
350
- self.assertRaises(KeyError, self.sim.set_constant, 'cell.Bert', 11)
351
-
352
- # Calculated constant
353
- self.assertRaisesRegex(
354
- ValueError, 'not a literal', self.sim.set_constant, 'ina.ENa', 11)
355
-
356
- def test_short_runs(self):
357
- # Test for simulations run a very short time
358
-
359
- # Run for 1 unit (OK)
360
- self.sim.reset()
361
- self.sim.run(1)
362
-
363
- # Test running for 0 units doesn't affect state
364
- x0 = self.sim.state()
365
- self.sim.run(0)
366
- self.assertEqual(x0, self.sim.state())
367
- self.sim.run(0)
368
- self.assertEqual(x0, self.sim.state())
369
-
370
- # Test running between indistinguishable times doesn't affect state
371
- t = self.sim.time()
372
- d = 0.5 * sys.float_info.epsilon
373
- self.assertEqual(t, t + d)
374
- self.sim.run(d)
375
-
376
- # Test running between only just distinguishable times is fine
377
- self.sim.reset()
378
- self.sim.run(1)
379
- t = self.sim.time()
380
- d = 3 * sys.float_info.epsilon
381
- self.assertNotEqual(t, t + d)
382
- self.sim.run(d)
383
-
384
- # Test running between barely distinguishable times raises CVODE error.
385
- t = self.sim.time()
386
- d = 2 * sys.float_info.epsilon
387
- self.assertNotEqual(t, t + d)
388
- self.assertRaisesRegex(
389
- myokit.SimulationError, 'CV_TOO_CLOSE', self.sim.run, d)
390
-
391
- # Empty log times
392
- self.sim.reset()
393
- self.sim.run(1, log_times=[])
394
-
395
- # Non-monotonic times
396
- self.sim.reset()
397
- with self.assertRaisesRegex(ValueError, 'Values in log_times'):
398
- self.sim.run(1, log_times=[1, 2, 1])
399
-
400
- # Simultaneous use of log_times and log_interval
401
- self.sim.reset()
402
- with self.assertRaisesRegex(ValueError, 'The arguments log_times'):
403
- self.sim.run(1, log_times=[1, 2], log_interval=2)
404
-
405
- def test_simulation_error_1(self):
406
- # Test for simulation error detection: massive stimulus.
407
-
408
- # Silly protocol
409
- p = myokit.Protocol()
410
- p.schedule(level=1000, start=1, duration=1)
411
- self.sim.reset()
412
- self.sim.set_protocol(p)
413
- self.assertRaisesRegex(
414
- myokit.SimulationError, 'numerical error', self.sim.run, 10)
415
- self.sim.set_protocol(self.protocol)
416
-
417
- @unittest.skipIf(platform.system() != 'Linux', 'CVODE error tests')
418
- def test_simulation_error_2(self):
419
- # Test for simulation error detection: failure occurred too often.
420
-
421
- # Cvode error (test failure occurred too many times)
422
- m = self.model.clone()
423
- v = m.get('membrane.V')
424
- v.set_rhs(myokit.Multiply(v.rhs(), myokit.Number(1e18)))
425
- s = myokit.LegacySimulation(m, self.protocol)
426
- with WarningCollector():
427
- self.assertRaisesRegex(
428
- myokit.SimulationError, 'numerical error', s.run, 5000)
429
-
430
- def test_cvode_simulation_with_zero_states(self):
431
- # Tests running cvode simulations on models with no ODEs
432
-
433
- # Create a model without states
434
- m1 = myokit.Model()
435
- c = m1.add_component('c')
436
- t = c.add_variable('t')
437
- t.set_rhs(0)
438
- t.set_binding('time')
439
- v = c.add_variable('v')
440
- v.set_rhs('0')
441
- v.set_binding('pace')
442
- w = c.add_variable('w')
443
- w.set_rhs('2 * v')
444
-
445
- # Create a model with a state
446
- m2 = m1.clone()
447
- z = m2.get('c').add_variable('z')
448
- z.set_rhs(0.1)
449
- z.promote(0)
450
-
451
- # Test without protocol and dynamic logging
452
- s1 = myokit.LegacySimulation(m1)
453
- d1 = s1.run(5)
454
- self.assertEqual(len(d1.time()), 2)
455
- self.assertEqual(list(d1.time()), [0, 5])
456
- self.assertEqual(list(d1['c.w']), [0, 0])
457
- s2 = myokit.LegacySimulation(m2)
458
- d2 = s2.run(6, log_times=d1.time())
459
- self.assertEqual(d1.time(), d2.time())
460
- self.assertEqual(d1['c.w'], d2['c.w'])
461
-
462
- # Test with a protocol and dynamic logging
463
- p = myokit.Protocol()
464
- p.schedule(0, 0, 2)
465
- p.schedule(1, 2, 2)
466
- p.schedule(2, 4, 4)
467
- p.schedule(3, 8, 2)
468
- s1.reset()
469
- s1.set_protocol(p)
470
- d1 = s1.run(p.characteristic_time())
471
- self.assertEqual(len(d1.time()), 5)
472
- self.assertEqual(list(d1.time()), [0, 2, 4, 8, 10])
473
- self.assertEqual(list(d1['c.w']), [0, 2, 4, 6, 0])
474
- s2.reset()
475
- s2.set_protocol(p)
476
- d2 = s2.run(p.characteristic_time() + 1, log_times=d1.time())
477
- self.assertEqual(d1.time(), d2.time())
478
- self.assertEqual(d1['c.w'], d2['c.w'])
479
-
480
- # Test with fixed logging times
481
- s1.reset()
482
- d1 = s1.run(p.characteristic_time() + 1, log_times=d1['c.t'])
483
- self.assertEqual(list(d1.time()), [0, 2, 4, 8, 10])
484
- self.assertEqual(list(d1['c.w']), [0, 2, 4, 6, 0])
485
- s2.reset()
486
- d2 = s2.run(p.characteristic_time() + 1, log_times=d1.time())
487
- self.assertEqual(d1.time(), d2.time())
488
- self.assertEqual(d1['c.w'], d2['c.w'])
489
-
490
- # Test appending to log
491
- s1.reset()
492
- d1 = s1.run(5)
493
- d1 = s1.run(5, log=d1)
494
- self.assertEqual(list(d1.time()), [0, 2, 4, 5, 8, 10])
495
- self.assertEqual(list(d1['c.w']), [0, 2, 4, 4, 6, 0])
496
-
497
- # Test with a log interval
498
- s1.reset()
499
- d1 = s1.run(11, log_interval=1)
500
- self.assertEqual(list(d1.time()), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
501
- self.assertEqual(list(d1['c.w']), [0, 0, 2, 2, 4, 4, 4, 4, 6, 6, 0])
502
-
503
- def test_pickling(self):
504
- # Test pickling a simulation
505
-
506
- # Test with myokit.Protocol
507
- m, p, _ = myokit.load('example')
508
- s1 = myokit.LegacySimulation(m, p)
509
- s1.pre(123)
510
- s_bytes = pickle.dumps(s1)
511
- s2 = pickle.loads(s_bytes)
512
- self.assertEqual(s1.time(), s2.time())
513
- self.assertEqual(s1.state(), s2.state())
514
- self.assertEqual(s1.default_state(), s2.default_state())
515
- s1.run(123, log=myokit.LOG_NONE)
516
- s2.run(123, log=myokit.LOG_NONE)
517
- self.assertEqual(s1.time(), s2.time())
518
- self.assertEqual(s1.state(), s2.state())
519
-
520
- # Test simulation properties
521
- s1.set_tolerance(1e-8, 1e-8)
522
- s1.set_min_step_size(1e-2)
523
- s1.set_max_step_size(0.1)
524
- s2 = pickle.loads(pickle.dumps(s1))
525
- s1.run(23, log=myokit.LOG_NONE)
526
- s2.run(23, log=myokit.LOG_NONE)
527
- self.assertEqual(s1.time(), s2.time())
528
- self.assertEqual(s1.state(), s2.state())
529
-
530
- # Test changed constants
531
- s1.set_constant('membrane.C', 1.1)
532
- s2 = pickle.loads(pickle.dumps(s1))
533
- s1.run(17, log=myokit.LOG_NONE)
534
- s2.run(17, log=myokit.LOG_NONE)
535
- self.assertEqual(s1.time(), s2.time())
536
- self.assertEqual(s1.state(), s2.state())
537
-
538
- def test_sim_stats(self):
539
- # Test extraction of simulation statistics
540
- m, p, _ = myokit.load('example')
541
- rt = m['engine'].add_variable('realtime')
542
- rt.set_rhs(0)
543
- rt.set_binding('realtime')
544
- ev = m['engine'].add_variable('evaluations')
545
- ev.set_rhs(0)
546
- ev.set_binding('evaluations')
547
- s = myokit.LegacySimulation(m, p)
548
- d = s.run(100, log=myokit.LOG_BOUND).npview()
549
-
550
- self.assertIn('engine.realtime', d)
551
- self.assertIn('engine.evaluations', d)
552
- rt, ev = d['engine.realtime'], d['engine.evaluations']
553
- self.assertEqual(len(d.time()), len(rt))
554
- self.assertEqual(len(d.time()), len(ev))
555
- self.assertTrue(np.all(rt >= 0))
556
- self.assertTrue(np.all(ev >= 0))
557
- self.assertTrue(np.all(rt[1:] >= rt[:-1]))
558
- self.assertTrue(np.all(ev[1:] >= ev[:-1]))
559
-
560
- def test_apd(self):
561
- # Test the apd rootfinding routine
562
-
563
- s = myokit.LegacySimulation(
564
- self.model, self.protocol, apd_var='membrane.V')
565
- s.set_tolerance(1e-8, 1e-8)
566
- d, apds = s.run(1800, log=myokit.LOG_NONE, apd_threshold=-70)
567
-
568
- # Check with threshold equal to V
569
- self.assertEqual(len(apds['start']), 2)
570
- self.assertEqual(len(apds['duration']), 2)
571
- self.assertAlmostEqual(apds['start'][0], 1.19, places=1)
572
- self.assertAlmostEqual(apds['start'][1], 1001.19, places=1)
573
- self.assertAlmostEqual(apds['duration'][0], 383.88262, places=0)
574
- self.assertAlmostEqual(apds['duration'][1], 378.31448, places=0)
575
-
576
- def test_derivatives(self):
577
- # Tests logging of derivatives by comparing with a finite difference
578
- # approximation
579
-
580
- # Run past the upstroke, where finite diff approx is worst
581
- self.sim.reset()
582
- self.sim.run(52)
583
-
584
- # Now run logged part
585
- d = self.sim.run(600).npview()
586
- if False:
587
- import matplotlib.pyplot as plt
588
- plt.figure()
589
- ax = plt.subplot(3, 1, 1)
590
- ax.plot(d.time(), d['membrane.V'])
591
- ax = plt.subplot(3, 1, 2)
592
- ax.plot(d.time(), d['dot(membrane.V)'])
593
-
594
- # Get central difference approximation
595
- t = d.time()
596
- v = d['membrane.V']
597
- dv = (v[2:] - v[:-2]) / (t[2:] - t[:-2])
598
- e = d['dot(membrane.V)'][1:-1] - dv
599
- if False:
600
- t = t[1:-1]
601
- ax.plot(t, dv, '--')
602
- ax = plt.subplot(3, 1, 3)
603
- ax.plot(t, e)
604
- print(np.max(np.abs(e)))
605
-
606
- # Compare
607
- self.assertLess(np.max(np.abs(e)), 0.1)
608
-
609
-
610
- if __name__ == '__main__':
611
- unittest.main()
612
-