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
@@ -5,9 +5,6 @@
5
5
  # This file is part of Myokit.
6
6
  # See http://myokit.org for copyright, sharing, and licensing details.
7
7
  #
8
- from __future__ import absolute_import, division
9
- from __future__ import print_function, unicode_literals
10
-
11
8
  import os
12
9
  import pickle
13
10
  import platform
@@ -26,12 +23,6 @@ from myokit.tests import (
26
23
  WarningCollector,
27
24
  )
28
25
 
29
- # Unit testing in Python 2 and 3
30
- try:
31
- unittest.TestCase.assertRaisesRegex
32
- except AttributeError:
33
- unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
34
-
35
26
 
36
27
  class SimulationTest(unittest.TestCase):
37
28
  """
@@ -80,6 +71,162 @@ class SimulationTest(unittest.TestCase):
80
71
  d2 = self.sim.run(5, log_interval=-5)
81
72
  self.assertEqual(d1.time(), d2.time())
82
73
 
74
+ def test_multiple_protocols(self):
75
+ # Test using multiple protocols
76
+
77
+ # Set up a model
78
+ model = myokit.Model()
79
+ c = model.add_component('c')
80
+ t = c.add_variable('t')
81
+ t.set_binding('time')
82
+ t.set_rhs(0)
83
+
84
+ a = c.add_variable('a')
85
+ a.set_binding('a')
86
+ a.set_rhs(0)
87
+ b = c.add_variable('b')
88
+ b.set_binding('b')
89
+ b.set_rhs(0)
90
+ y = c.add_variable('y')
91
+ y.promote(1)
92
+ y.set_rhs('-a * y - b * y')
93
+
94
+ # Create two overlapping protocols
95
+ pa = myokit.Protocol()
96
+ pa.schedule(level=1, start=0.2, duration=0.5)
97
+
98
+ pb = myokit.Protocol()
99
+ pb.schedule(level=2, start=0.5, duration=0.6)
100
+
101
+ # Run a simulation with both
102
+ s = myokit.Simulation(model, {'a': pa, 'b': pb})
103
+ s.set_tolerance(1e-8)
104
+ d = s.run(2).npview()
105
+ times = d[t]
106
+
107
+ # Check that the changing points are in the log
108
+ self.assertIn(0, times)
109
+ self.assertIn(0.2, times)
110
+ self.assertIn(0.5, times)
111
+ self.assertIn(0.7, times)
112
+ self.assertIn(1.1, times)
113
+ self.assertIn(2, times)
114
+
115
+ # Check that a, b, and y have the expected values
116
+ a_up = (times >= 0.2) & (times < 0.7)
117
+ np.testing.assert_array_equal(d[a], np.where(a_up, 1, 0))
118
+
119
+ b_up = (times >= 0.5) & (times < 1.1)
120
+ np.testing.assert_array_equal(d[b], np.where(b_up, 2, 0))
121
+
122
+ # Check that dy/dt has the expected values
123
+ # dy/dt =
124
+ # 0 from 0 to 0.2
125
+ # -y from 0.2 to 0.5
126
+ # -3y from 0.5 to 0.7
127
+ # -2y from 0.7 to 1.1
128
+ # 0 after 1.1
129
+ #
130
+ dy_expect = 0 * times
131
+ dy_expect[a_up] -= 1 * d[y][a_up]
132
+ dy_expect[b_up] -= 2 * d[y][b_up]
133
+ np.testing.assert_array_equal(d['dot(c.y)'], dy_expect)
134
+
135
+ # Check that y has the expected values
136
+ # The solution for dy/dt = -a*y is y(t) = c * exp(-at), so
137
+ # y =
138
+ # 1
139
+ # exp(-(t - 0.5))
140
+ # exp(-0.3) * exp(-3 * (t - 0.5))
141
+ # exp(-0.9) * exp(-2 * (t - 0.7))
142
+ # exp(-1.7)
143
+ #
144
+ y_expect = np.ones(times.shape)
145
+ i = (times >= 0.2) & (times < 0.5)
146
+ y_expect[i] = np.exp(-(times[i] - 0.2))
147
+ i = (times >= 0.5) & (times < 0.7)
148
+ y_expect[i] = np.exp(-0.3) * np.exp(-3 * (times[i] - 0.5))
149
+ i = (times >= 0.7) & (times < 1.1)
150
+ y_expect[i] = np.exp(-0.9) * np.exp(-2 * (times[i] - 0.7))
151
+ y_expect[times >= 1.1] = np.exp(-1.7)
152
+ np.testing.assert_array_almost_equal(d[y], y_expect, decimal=3)
153
+
154
+ # Test unsetting
155
+ s.set_protocol(None, label='a')
156
+ s.reset()
157
+ d = s.run(2).npview()
158
+ np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
159
+ times = d[t]
160
+ b_up = (times >= 0.5) & (times < 1.1)
161
+ np.testing.assert_array_equal(d[b], np.where(b_up, 2, 0))
162
+ y_expect = np.ones(times.shape)
163
+ i = (times >= 0.5) & (times < 1.1)
164
+ y_expect[i] = np.exp(-2 * (times[i] - 0.5))
165
+ y_expect[times >= 1.1] = np.exp(-1.2)
166
+ np.testing.assert_array_almost_equal(d[y], y_expect, decimal=3)
167
+
168
+ # Test unsetting
169
+ s.set_protocol(None, label='b')
170
+ s.reset()
171
+ d = s.run(2).npview()
172
+ np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
173
+ np.testing.assert_array_equal(d[a], np.zeros(d[a].shape))
174
+ np.testing.assert_array_equal(d[y], np.ones(d[a].shape))
175
+
176
+ def test_mixed_protocols(self):
177
+ # Test using a step and a time series protocol at the same time
178
+
179
+ # Set up a model
180
+ model = myokit.Model()
181
+ c = model.add_component('c')
182
+ t = c.add_variable('t')
183
+ t.set_binding('time')
184
+ t.set_rhs(0)
185
+ a = c.add_variable('a')
186
+ a.set_binding('a')
187
+ a.set_rhs(0)
188
+ b = c.add_variable('b')
189
+ b.set_binding('b')
190
+ b.set_rhs(0)
191
+ y = c.add_variable('y') # Just to log more points
192
+ y.promote(1)
193
+ y.set_rhs('a + b')
194
+
195
+ # Set up protocols
196
+ pa = myokit.pacing.blocktrain(level=2, offset=1, duration=2, period=5)
197
+ x = np.linspace(0, 10, 100)
198
+ y = 0.1 + 0.2 * np.sin(x)
199
+ pb = myokit.TimeSeriesProtocol(x, y)
200
+
201
+ # Run a simulation with both
202
+ s = myokit.Simulation(model, {'a': pa, 'b': pb})
203
+ s.set_tolerance(1e-8)
204
+ d = s.run(12).npview()
205
+ t = d[t]
206
+
207
+ # Start, end, and change points visited exactly
208
+ self.assertIn(0, t)
209
+ self.assertIn(1, t)
210
+ self.assertIn(3, t)
211
+ self.assertIn(6, t)
212
+ self.assertIn(8, t)
213
+ self.assertIn(11, t)
214
+ self.assertIn(12, t)
215
+
216
+ # Test a
217
+ a_e = np.zeros(t.shape)
218
+ a_e[(t >= 1) & (t < 3)] = 2
219
+ a_e[(t >= 6) & (t < 8)] = 2
220
+ a_e[(t >= 11) & (t < 13)] = 2
221
+ np.testing.assert_array_equal(d[a], a_e)
222
+
223
+ # Test b
224
+ b_e = 0.1 + 0.2 * np.sin(t)
225
+ b_e[t > 10] = y[-1]
226
+ # Note: We don't expect a super good match here, as b_e is an exact
227
+ # sine value, while the solver will be interpolating y
228
+ np.testing.assert_array_almost_equal(d[b], b_e, decimal=3)
229
+
83
230
  def test_no_protocol(self):
84
231
  # Test running without a protocol.
85
232
 
@@ -91,50 +238,74 @@ class SimulationTest(unittest.TestCase):
91
238
  # Check if pace was set to zero (see prop 651 / technical docs).
92
239
  self.assertTrue(np.all(d['engine.pace'] == 0.0))
93
240
 
94
- def test_fixed_form_protocol(self):
95
- # Test running with a fixed form protocol.
241
+ def test_wrong_label_set_pacing(self):
242
+ # Test set_pacing with incorrect label
243
+ self.sim.reset()
244
+ self.sim.pre(50)
245
+ with self.assertRaisesRegex(ValueError, 'Unknown pacing label'):
246
+ self.sim.set_protocol(None, label='does not exist')
247
+
248
+ def test_time_series_protocol(self):
249
+ # Test running with a time series protocol
96
250
 
97
251
  n = 10
98
- time = list(range(n))
99
- pace = [0] * n
100
- pace[2:4] = [0.5, 0.5]
252
+ times = list(range(n))
253
+ values = [0] * n
254
+ values[2:4] = [0.5, 0.5]
255
+ p = myokit.TimeSeriesProtocol(times, values)
101
256
 
102
- self.sim.set_fixed_form_protocol(time, pace)
257
+ self.sim.set_protocol(p)
103
258
  self.sim.reset()
104
259
  d = self.sim.run(n, log_interval=1)
105
- self.assertEqual(list(d.time()), time)
106
- self.assertEqual(list(d['engine.pace']), pace)
260
+ self.assertEqual(list(d.time()), times)
261
+ self.assertEqual(list(d['engine.pace']), values)
107
262
 
108
263
  # Unset
109
- self.sim.set_fixed_form_protocol(None)
264
+ self.sim.set_protocol(None)
110
265
  self.sim.reset()
111
266
  d = self.sim.run(n, log_interval=1)
112
267
  self.assertEqual(list(d['engine.pace']), [0] * n)
113
268
 
114
269
  # Reset
115
- self.sim.set_fixed_form_protocol(time, pace)
270
+ self.sim.set_protocol(p)
116
271
  self.sim.reset()
117
272
  d = self.sim.run(n, log_interval=1)
118
- self.assertEqual(list(d.time()), time)
119
- self.assertEqual(list(d['engine.pace']), pace)
273
+ self.assertEqual(list(d.time()), times)
274
+ self.assertEqual(list(d['engine.pace']), values)
120
275
 
121
276
  # Unset, replace with original protocol
122
277
  self.sim.set_protocol(self.protocol)
123
278
  self.sim.reset()
124
279
  d = self.sim.run(n, log_interval=1)
125
- self.assertNotEqual(list(d['engine.pace']), pace)
280
+ self.assertNotEqual(list(d['engine.pace']), values)
126
281
  self.assertNotEqual(list(d['engine.pace']), [0] * n)
127
282
 
128
- # Invalid protocols
129
- self.assertRaisesRegex(
130
- ValueError, 'no times', self.sim.set_fixed_form_protocol,
131
- values=pace)
132
- self.assertRaisesRegex(
133
- ValueError, 'no values', self.sim.set_fixed_form_protocol,
134
- times=time)
135
- self.assertRaisesRegex(
136
- ValueError, 'same size', self.sim.set_fixed_form_protocol,
137
- time, pace[:-1])
283
+ # Deprecated version
284
+ with WarningCollector() as w:
285
+ self.sim.set_fixed_form_protocol(times, values)
286
+ self.assertIn('eprecated', w.text())
287
+ self.sim.reset()
288
+ d = self.sim.run(n, log_interval=1)
289
+ self.assertEqual(list(d.time()), times)
290
+ self.assertEqual(list(d['engine.pace']), values)
291
+ with WarningCollector() as w:
292
+ self.assertRaisesRegex(
293
+ ValueError, 'No times',
294
+ self.sim.set_fixed_form_protocol, values=values)
295
+ self.assertRaisesRegex(
296
+ ValueError, 'No values',
297
+ self.sim.set_fixed_form_protocol, times=times)
298
+ self.sim.set_fixed_form_protocol(None)
299
+ self.sim.reset()
300
+ d = self.sim.run(n, log_interval=1)
301
+ self.assertEqual(list(d['engine.pace']), [0] * n)
302
+
303
+ # Reset original protocol
304
+ self.sim.set_protocol(self.protocol)
305
+ self.sim.reset()
306
+ d = self.sim.run(n, log_interval=1)
307
+ self.assertNotEqual(list(d['engine.pace']), values)
308
+ self.assertNotEqual(list(d['engine.pace']), [0] * n)
138
309
 
139
310
  def test_in_parts(self):
140
311
  # Test running the simulation in parts.
@@ -154,6 +325,30 @@ class SimulationTest(unittest.TestCase):
154
325
  self.assertNotEqual(e['engine.time'][n - 1], e['engine.time'][n])
155
326
  self.assertGreater(e['engine.time'][n], e['engine.time'][n - 1])
156
327
 
328
+ def test_initial_value_expressions(self):
329
+ # Test if initial value expressions are converted to floats
330
+
331
+ m = myokit.parse_model('''
332
+ [[model]]
333
+ c.x = 1 + sqrt(3)
334
+ c.y = 1 / c.p
335
+ c.z = 3
336
+
337
+ [c]
338
+ t = 0 bind time
339
+ dot(x) = 1
340
+ dot(y) = 2
341
+ dot(z) = 3
342
+ p = log(3)
343
+ ''')
344
+ s = myokit.Simulation(m)
345
+ x = s.state()
346
+ self.assertIsInstance(x[0], float)
347
+ self.assertIsInstance(x[1], float)
348
+ self.assertIsInstance(x[2], float)
349
+ self.assertEqual(x, m.initial_values(True))
350
+ self.assertEqual(x, s.default_state())
351
+
157
352
  def test_pacing_values_at_event_transitions(self):
158
353
  # Tests the value of the pacing signal at event transitions
159
354
 
@@ -239,9 +434,34 @@ class SimulationTest(unittest.TestCase):
239
434
  progress=CancellingReporter(0))
240
435
 
241
436
  def test_apd_tracking(self):
242
- # Test the APD calculation method.
437
+ # Test the APD / rootfinding method.
438
+ # Tested against offline method in test_datalog.py
243
439
 
244
- # More testing is done in test_datalog.py!
440
+ # Test that it works
441
+ self.sim.reset()
442
+ res = self.sim.run(
443
+ 1800, log=['engine.time', 'membrane.V'],
444
+ apd_variable='membrane.V', apd_threshold=-70)
445
+
446
+ self.assertIsInstance(res, tuple)
447
+ self.assertEqual(len(res), 2)
448
+ d, apds = res
449
+ self.assertIsInstance(d, myokit.DataLog)
450
+ self.assertIsInstance(apds, myokit.DataLog)
451
+ self.assertEqual(len(apds), 2)
452
+ self.assertEqual(apds.length(), 2)
453
+ self.assertIn('start', apds)
454
+ self.assertAlmostEqual(apds['start'][0], 1, places=0)
455
+ self.assertAlmostEqual(apds['start'][1], 1001, places=0)
456
+ self.assertIn('start', apds)
457
+ self.assertAlmostEqual(apds['duration'][0], 383.877194, places=1)
458
+ self.assertAlmostEqual(apds['duration'][1], 378.315915, places=1)
459
+
460
+ # Works with variable objects too
461
+ self.sim.reset()
462
+ res = self.sim.run(
463
+ 1000, log=['engine.time', 'membrane.V'],
464
+ apd_variable=self.model.get('membrane.V'), apd_threshold=-70)
245
465
 
246
466
  # Apd var is not a state
247
467
  self.assertRaisesRegex(
@@ -335,12 +555,53 @@ class SimulationTest(unittest.TestCase):
335
555
  self.sim.set_state(s1)
336
556
  self.assertEqual(d1, self.sim.eval_derivatives())
337
557
 
338
- def test_sensitivites_initial(self):
558
+ def test_eval_derivatives_with_pacing(self):
559
+ # Test :meth:`Simulation.eval_derivatives()`.
560
+
561
+ model = myokit.Model()
562
+ c = model.add_component('c')
563
+
564
+ a = c.add_variable('a')
565
+ a.set_binding('a')
566
+ a.set_rhs(0)
567
+ b = c.add_variable('b')
568
+ b.set_binding('b')
569
+ b.set_rhs(0)
570
+
571
+ y = c.add_variable('y')
572
+ t = c.add_variable('t')
573
+ t.set_binding('time')
574
+ t.set_rhs(0)
575
+ y.promote(1)
576
+ y.set_rhs('- a * y - b * y')
577
+
578
+ pa = myokit.Protocol()
579
+ pa.schedule(1, 0, 0.5)
580
+
581
+ pb = myokit.Protocol()
582
+ pb.schedule(2, 1.0, 0.5)
583
+
584
+ sim = myokit.Simulation(model, {'a': pa, 'b': pb})
585
+ sim.run(1)
586
+ d1 = sim.eval_derivatives(pacing={'a': 0.5, 'b': 0.5})
587
+ d2 = sim.eval_derivatives(pacing={'a': 1.5, 'b': 0.5})
588
+ self.assertNotEqual(d1, d2)
589
+ d1 = sim.eval_derivatives(pacing={'b': 0.5})
590
+ d2 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.5})
591
+ self.assertEqual(d1, d2)
592
+ d1 = sim.eval_derivatives()
593
+ d2 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.0})
594
+ self.assertEqual(d1, d2)
595
+ d1 = sim.eval_derivatives(pacing={'a': 0.0, 'b': 0.5})
596
+ d2 = sim.eval_derivatives(pacing={'aaaaa': 1.0, 'b': 0.5})
597
+ self.assertEqual(d1, d2)
598
+
599
+ def test_sensitivities_initial(self):
339
600
  # Test setting initial sensitivity values.
340
601
 
341
602
  m = myokit.parse_model('''
342
603
  [[model]]
343
- e.y = 2.3
604
+ e.y = 1 + 1.3
344
605
 
345
606
  [e]
346
607
  t = 0 bind time
@@ -352,6 +613,26 @@ class SimulationTest(unittest.TestCase):
352
613
  #TODO: Test results
353
614
  s = myokit.Simulation(m, sensitivities=(['e.y'], ['e.p', 'init(e.y)']))
354
615
 
616
+ # Warn if a parameter sensitivity won't be picked up.
617
+ m = myokit.parse_model('''
618
+ [[model]]
619
+ c.x = 1 / c.p
620
+
621
+ [c]
622
+ t = 0 bind time
623
+ p = 1 / q
624
+ q = 5
625
+ r = 3
626
+ dot(x) = 2 + r
627
+ ''')
628
+ m.validate()
629
+ s = (['c.x'], ['c.q'])
630
+ self.assertRaisesRegex(
631
+ NotImplementedError, 'respect to parameters used in initial',
632
+ myokit.Simulation, m, sensitivities=s)
633
+ s = (['c.x'], ['c.r'])
634
+ s = myokit.Simulation(m, sensitivities=s)
635
+
355
636
  # Test bad initial matrix
356
637
  self.assertRaisesRegex(
357
638
  ValueError, 'None or a list',
@@ -539,8 +820,8 @@ class SimulationTest(unittest.TestCase):
539
820
  ''')
540
821
  m.validate()
541
822
 
542
- x0 = m.get('e.x').state_value()
543
- y0 = m.get('e.y').state_value()
823
+ x0 = m.get('e.x').initial_value(True)
824
+ y0 = m.get('e.y').initial_value(True)
544
825
  p = m.get('e.p').eval()
545
826
  q = m.get('e.q').eval()
546
827
  r = m.get('e.r').eval()
@@ -693,6 +974,7 @@ class SimulationTest(unittest.TestCase):
693
974
 
694
975
  # Literal
695
976
  self.sim.set_constant('cell.Na_i', 11)
977
+ self.sim.set_constant(self.model.get('cell.Na_i'), 11)
696
978
  self.assertRaises(KeyError, self.sim.set_constant, 'cell.Bert', 11)
697
979
 
698
980
  # Parameter (needs sensitivies set)
@@ -786,6 +1068,7 @@ class SimulationTest(unittest.TestCase):
786
1068
  z.promote(0)
787
1069
 
788
1070
  # Test without protocol and dynamic logging
1071
+ #myokit.DEBUG_WG = True
789
1072
  s1 = myokit.Simulation(m1)
790
1073
  d1 = s1.run(5)
791
1074
  self.assertEqual(len(d1.time()), 2)
@@ -886,23 +1169,6 @@ class SimulationTest(unittest.TestCase):
886
1169
  self.assertTrue(np.all(rt[1:] >= rt[:-1]))
887
1170
  self.assertTrue(np.all(ev[1:] >= ev[:-1]))
888
1171
 
889
- def test_apd(self):
890
- # Test the apd rootfinding routine
891
-
892
- s = myokit.Simulation(self.model, self.protocol)
893
- s.set_tolerance(1e-8, 1e-8)
894
- d, apds = s.run(
895
- 1800, log=myokit.LOG_NONE,
896
- apd_variable='membrane.V', apd_threshold=-70)
897
-
898
- # Check with threshold equal to V
899
- self.assertEqual(len(apds['start']), 2)
900
- self.assertEqual(len(apds['duration']), 2)
901
- self.assertAlmostEqual(apds['start'][0], 1.19, places=1)
902
- self.assertAlmostEqual(apds['start'][1], 1001.19, places=1)
903
- self.assertAlmostEqual(apds['duration'][0], 383.88262, places=1)
904
- self.assertAlmostEqual(apds['duration'][1], 378.31448, places=1)
905
-
906
1172
  def test_derivatives(self):
907
1173
  # Tests logging of derivatives by comparing with a finite difference
908
1174
  # approximation
@@ -5,9 +5,6 @@
5
5
  # This file is part of Myokit.
6
6
  # See http://myokit.org for copyright, sharing, and licensing details.
7
7
  #
8
- from __future__ import absolute_import, division
9
- from __future__ import print_function, unicode_literals
10
-
11
8
  import os
12
9
  import unittest
13
10
 
@@ -5,11 +5,9 @@
5
5
  # This file is part of Myokit.
6
6
  # See http://myokit.org for copyright, sharing, and licensing details.
7
7
  #
8
- from __future__ import absolute_import, division
9
- from __future__ import print_function, unicode_literals
10
-
11
8
  import os
12
9
  import unittest
10
+
13
11
  import numpy as np
14
12
 
15
13
  import myokit
@@ -21,13 +19,6 @@ from myokit.tests import (
21
19
  WarningCollector,
22
20
  )
23
21
 
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
22
  # Show simulation output
32
23
  debug = False
33
24
 
@@ -535,7 +526,7 @@ class FiberTissueSimulationTest(unittest.TestCase):
535
526
  m = self.mf.count_states()
536
527
  nx, ny = self.nfx, self.nfy
537
528
 
538
- sm = self.mf.state()
529
+ sm = self.mf.initial_values(True)
539
530
  for i in range(nx):
540
531
  for j in range(ny):
541
532
  self.assertEqual(sm, self.s1.fiber_state(i, j))
@@ -622,6 +613,42 @@ class FiberTissueSimulationTest(unittest.TestCase):
622
613
  finally:
623
614
  self.s1.reset()
624
615
 
616
+ def test_initial_value_expressions(self):
617
+ # Test if initial value expressions are converted to floats
618
+ m = myokit.parse_model('''
619
+ [[model]]
620
+ c.x = 1 + sqrt(3)
621
+ c.y = 1 / c.p
622
+ c.z = 3
623
+
624
+ [c]
625
+ t = 0 bind time
626
+ dot(x) = 1 label membrane_potential
627
+ in [mV]
628
+ dot(y) = 2
629
+ dot(z) = 3
630
+ p = log(3)
631
+ q = 0 bind diffusion_current
632
+ in [A/F]
633
+ ''')
634
+ s = myokit.FiberTissueSimulation(
635
+ m, m, ncells_fiber=(1, 1), ncells_tissue=(3, 1))
636
+ x = s.fiber_state()
637
+ self.assertIsInstance(x[0], float)
638
+ self.assertIsInstance(x[1], float)
639
+ self.assertIsInstance(x[2], float)
640
+ self.assertEqual(x, m.initial_values(True))
641
+ self.assertEqual(x, s.default_fiber_state())
642
+
643
+ x = s.tissue_state()
644
+ self.assertIsInstance(x[0], float)
645
+ self.assertIsInstance(x[1], float)
646
+ self.assertIsInstance(x[2], float)
647
+ self.assertEqual(x[:3], x[3:6])
648
+ self.assertEqual(x[:3], x[6:])
649
+ self.assertEqual(x, m.initial_values(True) * 3)
650
+ self.assertEqual(x, s.default_tissue_state())
651
+
625
652
  def test_tissue_state(self):
626
653
  # Test the set_tissue_state and set_default_tissue_state methods
627
654
 
@@ -629,7 +656,7 @@ class FiberTissueSimulationTest(unittest.TestCase):
629
656
  m = self.mt.count_states()
630
657
  nx, ny = self.ntx, self.nty
631
658
 
632
- sm = self.mt.state()
659
+ sm = self.mt.initial_values(True)
633
660
  for i in range(nx):
634
661
  for j in range(ny):
635
662
  self.assertEqual(sm, self.s1.tissue_state(i, j))