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
myokit/_sim/cvodessim.py CHANGED
@@ -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 platform
13
10
  import tempfile
@@ -85,7 +82,7 @@ class Simulation(myokit.CModule):
85
82
  determined using the protocol passed into the Simulation.
86
83
  ``evaluations``
87
84
  This input provides the number of rhs evaluations used at each point in
88
- time and can be used to gain some insight into the solver's behaviour.
85
+ time and can be used to gain some insight into the solver's behavior.
89
86
  ``realtime``
90
87
  This input provides the elapsed system time at each logged point.
91
88
 
@@ -99,8 +96,8 @@ class Simulation(myokit.CModule):
99
96
 
100
97
  Each time a simulation is created, a C module is compiled, imported, and
101
98
  deleted in the background. This means that part of a ``Simulation`` object
102
- is a reference to an imported C extension, and cannot be serialised. When
103
- using ``pickle`` to serialise the simulation, this compiled part is not
99
+ is a reference to an imported C extension, and cannot be serialized. When
100
+ using ``pickle`` to serialize the simulation, this compiled part is not
104
101
  stored. Instead, when the pickled simulation is read from disk the
105
102
  compilation is repeated. Unpickling simulations also restores their state:
106
103
  variables such as model state, simulation time, and tolerance are preserved
@@ -122,8 +119,11 @@ class Simulation(myokit.CModule):
122
119
  ``model``
123
120
  The model to simulate
124
121
  ``protocol``
125
- An optional :class:`myokit.Protocol` to use as input for variables
126
- bound to ``pace``.
122
+ A :class:`myokit.Protocol` or :class:`myokit.TimeSeriesProtocol` to use
123
+ for the variable with binding ``pace``. Atlernatively, a dictionary
124
+ mapping binding labels to :class:`myokit.Protocol` objects can be used
125
+ to run with multiple protocols. Finally, can be ``None`` to run without
126
+ a protocol.
127
127
  ``sensitivities``
128
128
  An optional tuple ``(dependents, independents)`` where ``dependents``
129
129
  is a list of variables or expressions to take derivatives of (``y`` in
@@ -149,7 +149,7 @@ class Simulation(myokit.CModule):
149
149
  _index = 0 # Simulation id
150
150
 
151
151
  def __init__(self, model, protocol=None, sensitivities=None, path=None):
152
- super(Simulation, self).__init__()
152
+ super().__init__()
153
153
 
154
154
  # Require a valid model
155
155
  if not model.is_valid():
@@ -158,15 +158,34 @@ class Simulation(myokit.CModule):
158
158
  del model
159
159
 
160
160
  # Set protocol
161
- self._protocol = None
162
- self._fixed_form_protocol = None
163
- self.set_protocol(protocol)
164
- del protocol
161
+ self._protocols = []
162
+ self._pacing_labels = []
163
+ if isinstance(protocol, (myokit.Protocol, myokit.TimeSeriesProtocol)):
164
+ protocol = {'pace': protocol}
165
+ elif protocol is None:
166
+ # TODO: This can be an empty dict once #320 is resolved
167
+ protocol = {'pace': None}
168
+ for label, protocol in protocol.items():
169
+ self._pacing_labels.append(label)
170
+ self._protocols.append(myokit.Protocol())
171
+ self.set_protocol(protocol, label)
165
172
 
166
173
  # Generate C Model code, get sensitivity and constants info
167
- cmodel = myokit.CModel(self._model, sensitivities)
174
+ cmodel = myokit.CModel(self._model, self._pacing_labels, sensitivities)
168
175
  if cmodel.has_sensitivities:
169
176
  self._sensitivities = (cmodel.dependents, cmodel.independents)
177
+
178
+ # Check for sensitivities w.r.t. variables used in initial state
179
+ # expressions. This is not implemented yet.
180
+ inits = self._model.initial_values()
181
+ for i in self._sensitivities[1]: # Expressions
182
+ if isinstance(i, myokit.Name):
183
+ for e in inits:
184
+ if e.depends_on(i, deep=True):
185
+ raise NotImplementedError(
186
+ 'Sensitivities with respect to parameters used'
187
+ ' in initial conditions is not implemented ('
188
+ + e.code() + ' depends on ' + i.code() + ').')
170
189
  else:
171
190
  self._sensitivities = None
172
191
 
@@ -186,19 +205,19 @@ class Simulation(myokit.CModule):
186
205
  del cmodel
187
206
 
188
207
  # Get state and default state from model
189
- self._state = self._model.state()
208
+ self._state = self._model.initial_values(as_floats=True)
190
209
  self._default_state = list(self._state)
191
210
 
192
211
  # Set state and default state for sensitivities
193
212
  self._s_state = self._s_default_state = None
194
213
  if self._sensitivities:
195
- # Outer indice: number of independent variables
196
- # Inner indice: number of states
214
+ # Outer index: number of independent variables
215
+ # Inner index: number of states
197
216
  self._s_state = []
198
217
  for expr in self._sensitivities[1]:
199
218
  row = [0.0] * len(self._state)
200
219
  if isinstance(expr, myokit.InitialValue):
201
- row[expr.var().indice()] = 1.0
220
+ row[expr.var().index()] = 1.0
202
221
  self._s_state.append(row)
203
222
  self._s_default_state = [list(x) for x in self._s_state]
204
223
 
@@ -281,13 +300,14 @@ class Simulation(myokit.CModule):
281
300
  if self._sensitivities:
282
301
  sens_arg = [[x.code() for x in y] for y in self._sensitivities]
283
302
 
284
- # Store serialised name and constructor args
303
+ # Store serialized name and constructor args
285
304
  fname = os.path.join(d_build, '_simulation.pickle')
286
305
  import pickle
287
306
  with open(fname, 'wb') as f:
288
307
  pickle.dump(str(name), f)
289
308
  pickle.dump(self._model, f)
290
- pickle.dump(self._protocol, f)
309
+ pickle.dump(self._protocols, f)
310
+ pickle.dump(self._pacing_labels, f)
291
311
  pickle.dump(sens_arg, f)
292
312
 
293
313
  # Zip it all in
@@ -327,13 +347,14 @@ class Simulation(myokit.CModule):
327
347
  with zipfile.ZipFile(path, 'r', zipfile.ZIP_DEFLATED) as f:
328
348
  f.extractall(d_build)
329
349
 
330
- # Load serialised name and constructor args
350
+ # Load serialized name and constructor args
331
351
  fname = os.path.join(d_build, '_simulation.pickle')
332
352
  import pickle
333
353
  with open(fname, 'rb') as f:
334
354
  name = pickle.load(f)
335
355
  model = pickle.load(f)
336
- protocol = pickle.load(f)
356
+ protocols = pickle.load(f)
357
+ pacing_labels = pickle.load(f)
337
358
  sensitivities = pickle.load(f)
338
359
 
339
360
  # Load module
@@ -341,7 +362,12 @@ class Simulation(myokit.CModule):
341
362
  module = load_module(name, d_build)
342
363
 
343
364
  # Create and return simulation
344
- return Simulation(model, protocol, sensitivities, (path, module))
365
+ labeled_protocols = {
366
+ k: v for k, v in zip(pacing_labels, protocols)
367
+ }
368
+ return Simulation(
369
+ model, labeled_protocols, sensitivities, (path, module)
370
+ )
345
371
 
346
372
  finally:
347
373
  myokit.tools.rmtree(d_build, silent=True)
@@ -372,12 +398,16 @@ class Simulation(myokit.CModule):
372
398
  """
373
399
  return list(self._error_state) if self._error_state else None
374
400
 
375
- def eval_derivatives(self, y=None):
401
+ def eval_derivatives(self, y=None, pacing=None):
376
402
  """
377
403
  Evaluates and returns the state derivatives.
378
404
 
379
405
  The state to evaluate for can be given as ``y``. If no state is given
380
406
  the current simulation state is used.
407
+
408
+ An optional dict ``pacing`` can be passed in that maps labels to
409
+ numerical values. If a label is used but not provided in ``pacing``,
410
+ it's value will be set to 0.
381
411
  """
382
412
  # Get state
383
413
  if y is None:
@@ -385,6 +415,15 @@ class Simulation(myokit.CModule):
385
415
  else:
386
416
  y = self._model.map_to_state(y)
387
417
 
418
+ pacing_values = [0.0] * len(self._pacing_labels)
419
+ if pacing is not None:
420
+ for k, v in pacing.items():
421
+ try:
422
+ ki = self._pacing_labels.index(k)
423
+ pacing_values[ki] = float(v)
424
+ except ValueError:
425
+ pass
426
+
388
427
  # Create space to store derivatives
389
428
  dy = list(self._state)
390
429
 
@@ -393,7 +432,7 @@ class Simulation(myokit.CModule):
393
432
  # 0. Time
394
433
  0,
395
434
  # 1. Pace
396
- 0,
435
+ pacing_values,
397
436
  # 2. State
398
437
  y,
399
438
  # 3. Space to store the state derivatives
@@ -467,7 +506,7 @@ class Simulation(myokit.CModule):
467
506
  for i, expr in enumerate(self._sensitivities[1]):
468
507
  if isinstance(expr, myokit.InitialValue):
469
508
  self._s_state[i] = [0.0] * len(self._state)
470
- self._s_state[i][expr.var().indice()] = 1.0
509
+ self._s_state[i][expr.var().index()] = 1.0
471
510
  # Update default state
472
511
  self._s_default_state = [list(x) for x in self._s_state]
473
512
 
@@ -484,16 +523,19 @@ class Simulation(myokit.CModule):
484
523
  # etc.
485
524
  sens_arg = [[x.code() for x in y] for y in self._sensitivities]
486
525
 
526
+ protocols = {
527
+ k: p for k, p in zip(self._pacing_labels, self._protocols)
528
+ }
529
+
487
530
  return (
488
531
  self.__class__,
489
- (self._model, self._protocol, sens_arg),
532
+ (self._model, protocols, sens_arg),
490
533
  (
491
534
  self._time,
492
535
  self._state,
493
536
  self._default_state,
494
537
  self._s_state,
495
538
  self._s_default_state,
496
- self._fixed_form_protocol, # Can't be set in constructor
497
539
  self._tolerance,
498
540
  self._dtmin,
499
541
  self._dtmax,
@@ -601,8 +643,8 @@ class Simulation(myokit.CModule):
601
643
 
602
644
  However, if sensitivity calculations are enabled a tuple is returned,
603
645
  where the first entry is the :class:`myokit.DataLog` and the second
604
- entry is a matrix of sensitivities ``dy/dx``, where the first indice
605
- specifies the dependent variable ``y``, and the second indice specifies
646
+ entry is a matrix of sensitivities ``dy/dx``, where the first index
647
+ specifies the dependent variable ``y``, and the second index specifies
606
648
  the independent variable ``x``.
607
649
 
608
650
  Finally, if APD calculation is enabled, the method returns a tuple
@@ -671,7 +713,7 @@ class Simulation(myokit.CModule):
671
713
 
672
714
  # APD measuring
673
715
  root_list = None
674
- root_indice = 0
716
+ root_index = 0
675
717
  root_threshold = 0
676
718
  if apd_variable is None:
677
719
  if apd_threshold is not None:
@@ -688,7 +730,7 @@ class Simulation(myokit.CModule):
688
730
 
689
731
  # Set up root finding
690
732
  root_list = []
691
- root_indice = apd_variable.indice()
733
+ root_index = apd_variable.index()
692
734
  root_threshold = float(apd_threshold)
693
735
 
694
736
  # Get progress indication function (if any)
@@ -721,7 +763,7 @@ class Simulation(myokit.CModule):
721
763
  s_state = [list(x) for x in self._s_state]
722
764
 
723
765
  # List to store final bound variables in (for debugging)
724
- bound = [0, 0, 0, 0]
766
+ bound = [0, 0, 0] + [0] * len(self._pacing_labels)
725
767
 
726
768
  # Initialize
727
769
  if myokit.DEBUG_SP:
@@ -741,30 +783,28 @@ class Simulation(myokit.CModule):
741
783
  list(self._literals.values()),
742
784
  # 6. Parameter values
743
785
  list(self._parameters.values()),
744
- # 7. An event-based pacing protocol
745
- self._protocol,
746
- # 8. A fixed-form protocol
747
- self._fixed_form_protocol,
748
- # 9. A DataLog
786
+ # 7. Pacing protocols
787
+ self._protocols,
788
+ # 8. A DataLog
749
789
  log,
750
- # 10. The log interval, or 0
790
+ # 9. The log interval, or 0
751
791
  log_interval,
752
- # 11. A list of predetermind logging times, or None
792
+ # 10. A list of predetermind logging times, or None
753
793
  log_times,
754
- # 12. A list to store calculated sensitivities in
794
+ # 11. A list to store calculated sensitivities in
755
795
  sensitivities,
756
- # 13. The state variable indice for root finding (only used if
796
+ # 12. The state variable index for root finding (only used if
757
797
  # root_list is a list)
758
- root_indice,
759
- # 14. The threshold for root crossing (can be 0 too, only used
798
+ root_index,
799
+ # 13. The threshold for root crossing (can be 0 too, only used
760
800
  # if root_list is a list).
761
801
  root_threshold,
762
- # 15. A list to store calculated root crossing times and
802
+ # 14. A list to store calculated root crossing times and
763
803
  # directions in, or None
764
804
  root_list,
765
- # 16. A myokit.tools.Benchmarker or None (if not used)
805
+ # 15. A myokit.tools.Benchmarker or None (if not used)
766
806
  b,
767
- # 17. Boolean/int: 1 if we are logging realtime
807
+ # 16. Boolean/int: 1 if we are logging realtime
768
808
  int(self._model.binding('realtime') is not None),
769
809
  )
770
810
  t = tmin
@@ -800,9 +840,12 @@ class Simulation(myokit.CModule):
800
840
  in self._model.format_state(state).splitlines()])
801
841
  txt.append('Inputs for binding:')
802
842
  txt.append(' time = ' + myokit.float.str(bound[0]))
803
- txt.append(' pace = ' + myokit.float.str(bound[1]))
804
- txt.append(' realtime = ' + myokit.float.str(bound[2]))
805
- txt.append(' evaluations = ' + myokit.float.str(bound[3]))
843
+ txt.append(' realtime = ' + myokit.float.str(bound[1]))
844
+ txt.append(' evaluations = ' + myokit.float.str(bound[2]))
845
+ for i, label in enumerate(self._pacing_labels):
846
+ txt.append(
847
+ ' ' + label + ' = ' + myokit.float.str(bound[3 + i])
848
+ )
806
849
  txt.append(str(e))
807
850
 
808
851
  # Check if state derivatives can be evaluated in Python, if
@@ -903,7 +946,7 @@ class Simulation(myokit.CModule):
903
946
 
904
947
  def set_default_state(self, state):
905
948
  """
906
- Allows you to manually set the default state.
949
+ Change the default state to ``state``.
907
950
  """
908
951
  self._default_state = self._model.map_to_state(state)
909
952
 
@@ -939,66 +982,51 @@ class Simulation(myokit.CModule):
939
982
 
940
983
  def set_fixed_form_protocol(self, times=None, values=None):
941
984
  """
942
- Configures this simulation to run with a predetermined protocol
943
- instead of the usual event-based mechanism.
944
-
945
- A 1D time-series should be given as input. During the simulation, the
946
- value of the pacing variable will be determined by linearly
947
- interpolating between the two nearest points in the series. If the
948
- simulation time is outside the bounds of the time-series, the first or
949
- last value in the series will be used.
950
-
951
- Setting a predetermined protocol clears any previously set (event-based
952
- or pre-determined) protocol. To clear all protocols, call this method
953
- with `times=None`. When a simulation is run without any protocol, the
954
- value of any variables bound to `pace` will be set to 0.
955
-
956
- Arguments:
957
-
958
- ``times``
959
- A non-decreasing array of times. If any times appear more than
960
- once, only the value at the highest index will be used.
961
- ``values``
962
- An array of values for the pacing variable. Must have the same size
963
- as ``times``.
985
+ Sets a :class:`TimeSeriesProtocol` specified by ``times`` and
986
+ ``values`` for the label ``pace``.
964
987
 
988
+ This method is provided for backwards compatibility with older
989
+ versions, please use :meth:`set_protocol` and the
990
+ :class:`TimeSeriesProtocol` class instead.
965
991
  """
966
- # Check input
967
- if times is None:
968
- if values is not None:
969
- raise ValueError('Values array given, but no times array.')
970
- else:
971
- if values is None:
972
- raise ValueError('Times array given, but no values array.')
973
- if len(times) != len(values):
974
- raise ValueError('Times and values array must have same size.')
975
-
976
- # Clear event-based protocol, if set
977
- self._protocol = None
992
+ # Deprecated on 2023-06-02
993
+ import warnings
994
+ warnings.warn(
995
+ 'The method `myokit.Simulation.set_fixed_form_protocol` is '
996
+ 'deprecated. It will be removed in future versions of Myokit.'
997
+ )
978
998
 
979
- # Set new protocol
999
+ if times is None and values is None:
1000
+ self.set_protocol(None)
1001
+ return
980
1002
  if times is None:
981
- # Clear predetermined protocol
982
- self._fixed_form_protocol = None
983
- else:
984
- # Copy data and set
985
- self._fixed_form_protocol = (list(times), list(values))
1003
+ raise ValueError('No times given.')
1004
+ if values is None:
1005
+ raise ValueError('No values given.')
1006
+
1007
+ self.set_protocol(myokit.TimeSeriesProtocol(times, values))
986
1008
 
987
- def set_protocol(self, protocol=None):
1009
+ def set_protocol(self, protocol, label='pace'):
988
1010
  """
989
- Sets the pacing :class:`Protocol` used by this simulation.
1011
+ Set an event-based pacing :class:`Protocol` or a :class:`FixedProtocol`
1012
+ for the given ``label``.
990
1013
 
991
- To run without pacing call this method with ``protocol = None``. In
992
- this case, the value of any variables bound to `pace` will be set to 0.
1014
+ To remove a previously set binding call this method with ``protocol =
1015
+ None``. In this case, the value of any variables bound to ``label``
1016
+ will be set to 0.
1017
+
1018
+ The label must be one of the pacing labels set in the constructor.
993
1019
  """
994
- # Clear predetermined protocol, if set
995
- self._fixed_form_protocol = None
1020
+ try:
1021
+ index = self._pacing_labels.index(label)
1022
+ except ValueError:
1023
+ raise ValueError('Unknown pacing label: ' + str(label))
996
1024
 
997
1025
  # Set new protocol
998
1026
  if protocol is None:
999
- self._protocol = None
1027
+ self._protocols[index] = myokit.Protocol()
1000
1028
  else:
1001
- self._protocol = protocol.clone()
1029
+ self._protocols[index] = protocol.clone()
1002
1030
 
1003
1031
  def __setstate__(self, state):
1004
1032
  """
@@ -1012,13 +1040,12 @@ class Simulation(myokit.CModule):
1012
1040
  self._default_state = state[2]
1013
1041
  self._s_state = state[3]
1014
1042
  self._s_default_state = state[4]
1015
- self._fixed_form_protocol = state[5]
1016
1043
 
1017
1044
  # The following properties need to be set on the internal simulation
1018
1045
  # object
1019
- self.set_tolerance(*state[6])
1020
- self.set_min_step_size(state[7])
1021
- self.set_max_step_size(state[8])
1046
+ self.set_tolerance(*state[5])
1047
+ self.set_min_step_size(state[6])
1048
+ self.set_max_step_size(state[7])
1022
1049
 
1023
1050
  def set_state(self, state):
1024
1051
  """
@@ -18,8 +18,8 @@
18
18
  *
19
19
  * // Create a and b as differentials. Both have derivative 1 with respect to
20
20
  * // themselves. This can be indicated explicitly or, as in this example,
21
- * // using the constructor arguments (value, indice) where indice is the
22
- * // indice of this variable in the list of derivatives.
21
+ * // using the constructor arguments (value, index) where index is the
22
+ * // index of this variable in the list of derivatives.
23
23
  * Diff a = Diff(2, 0);
24
24
  * Diff b = Diff(3, 1);
25
25
  * Diff x = 5 * a + pow(b, 2);
@@ -67,8 +67,8 @@
67
67
  static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
68
68
  #define NAN (*(const float *) __nan)
69
69
  #endif
70
-
71
-
70
+
71
+
72
72
  /*
73
73
  * Covector. A tiny, fixed size array class that allows addition and scalar
74
74
  * multiplication.
@@ -542,9 +542,7 @@ sim_init(PyObject* self, PyObject* args)
542
542
  for(i=0; i < nfx * nfy * n_state_f; i++) {
543
543
  flt = PyList_GetItem(state_in_f, i); // Don't decref!
544
544
  if(!PyFloat_Check(flt)) {
545
- char errstr[200];
546
- sprintf(errstr, "Item %u in fiber state vector is not a float.", (unsigned int)i);
547
- PyErr_SetString(PyExc_Exception, errstr);
545
+ PyErr_Format(PyExc_Exception, "Item %u in fiber state vector is not a float.", (unsigned int)i);
548
546
  return sim_clean();
549
547
  }
550
548
  rvec_state_f[i] = (Real)PyFloat_AsDouble(flt);
@@ -558,9 +556,7 @@ sim_init(PyObject* self, PyObject* args)
558
556
  for(i=0; i < ntx * nty * n_state_t; i++) {
559
557
  flt = PyList_GetItem(state_in_t, i);
560
558
  if(!PyFloat_Check(flt)) {
561
- char errstr[200];
562
- sprintf(errstr, "Item %u in tissue state vector is not a float.", (unsigned int)i);
563
- PyErr_SetString(PyExc_Exception, errstr);
559
+ PyErr_Format(PyExc_Exception, "Item %u in tissue state vector is not a float.", (unsigned int)i);
564
560
  return sim_clean();
565
561
  }
566
562
  rvec_state_t[i] = (Real)PyFloat_AsDouble(flt);
@@ -874,7 +870,7 @@ if var is not None:
874
870
  <?
875
871
  for var in modelf.states():
876
872
  print(3*tab + 'sprintf(log_var_name, "%u.%u.' + var.qname() + '", (unsigned int)j, (unsigned int)i);' )
877
- print(3*tab + 'if(log_add(log_dict_f, logs_f, vars_f, k_vars, log_var_name, &rvec_state_f[(i*nfx+j)*n_state_f+' + str(var.indice()) + '])) {')
873
+ print(3*tab + 'if(log_add(log_dict_f, logs_f, vars_f, k_vars, log_var_name, &rvec_state_f[(i*nfx+j)*n_state_f+' + str(var.index()) + '])) {')
878
874
  print(4*tab + 'logging_states_f = 1;')
879
875
  print(4*tab + 'k_vars++;')
880
876
  print(3*tab + '}')
@@ -945,7 +941,7 @@ if var is not None:
945
941
  <?
946
942
  for var in modelt.states():
947
943
  print(3*tab + 'sprintf(log_var_name, "%u.%u.' + var.qname() + '", (unsigned int)j, (unsigned int)i);' )
948
- print(3*tab + 'if(log_add(log_dict_t, logs_t, vars_t, k_vars, log_var_name, &rvec_state_t[(i*ntx+j)*n_state_t+' + str(var.indice()) + '])) {')
944
+ print(3*tab + 'if(log_add(log_dict_t, logs_t, vars_t, k_vars, log_var_name, &rvec_state_t[(i*ntx+j)*n_state_t+' + str(var.index()) + '])) {')
949
945
  print(4*tab + 'logging_states_t = 1;')
950
946
  print(4*tab + 'k_vars++;')
951
947
  print(3*tab + '}')
@@ -4,13 +4,11 @@
4
4
  # This file is part of Myokit.
5
5
  # See http://myokit.org for copyright, sharing, and licensing details.
6
6
  #
7
- from __future__ import absolute_import, division
8
- from __future__ import print_function, unicode_literals
9
-
10
7
  import os
11
- import myokit
12
8
  import platform
13
9
 
10
+ import myokit
11
+
14
12
  # Location of C and OpenCL sources
15
13
  SOURCE_FILE = 'fiber_tissue.c'
16
14
  KERNEL_FILE = 'openclsim.cl'
@@ -60,7 +58,7 @@ class FiberTissueSimulation(myokit.CModule):
60
58
  ``pace`` (per-cell)
61
59
  The pacing level, this is set if a protocol was passed in.
62
60
  ``diffusion_current`` (per-cell)
63
- The current flowing from the cell to its neighbours. This will be
61
+ The current flowing from the cell to its neighbors. This will be
64
62
  positive when the cell is acting as a source, negative when it is
65
63
  acting as a sink.
66
64
 
@@ -122,7 +120,7 @@ class FiberTissueSimulation(myokit.CModule):
122
120
  ncells_fiber=(128, 2), ncells_tissue=(128, 128), nx_paced=5,
123
121
  g_fiber=(9, 6), g_tissue=(9, 6), g_fiber_tissue=9,
124
122
  dt=0.005, precision=myokit.SINGLE_PRECISION, native_maths=False):
125
- super(FiberTissueSimulation, self).__init__()
123
+ super().__init__()
126
124
 
127
125
  # Deprecated since 2021-05-28
128
126
  # Un-deprecated on 2022-04-20, following Adam's request
@@ -303,19 +301,19 @@ class FiberTissueSimulation(myokit.CModule):
303
301
  ' and the tissue model: ' + str(ucf) + ' vs ' + str(uct) + '.')
304
302
 
305
303
  # Set state and default state
306
- self._statef = self._modelf.state() * self._ntotalf
307
- self._statet = self._modelt.state() * self._ntotalt
304
+ self._statef = self._modelf.initial_values(True) * self._ntotalf
305
+ self._statet = self._modelt.initial_values(True) * self._ntotalt
308
306
  self._default_statef = list(self._statef)
309
307
  self._default_statet = list(self._statet)
310
308
 
311
309
  # Process bindings, remove unsupported bindings, get map of bound
312
310
  # variables to internal names.
313
- self._bound_variablesf = self._modelf.prepare_bindings({
311
+ self._bound_variablesf = myokit._prepare_bindings(self._modelf, {
314
312
  'time': 'time',
315
313
  'pace': 'pace',
316
314
  'diffusion_current': 'idiff',
317
315
  })
318
- self._bound_variablest = self._modelt.prepare_bindings({
316
+ self._bound_variablest = myokit._prepare_bindings(self._modelt, {
319
317
  'time': 'time',
320
318
  'pace': 'pace',
321
319
  'diffusion_current': 'idiff',
@@ -676,7 +674,7 @@ class FiberTissueSimulation(myokit.CModule):
676
674
 
677
675
  # Get value causing error
678
676
  if var.is_state():
679
- value = states[1 if ifirst > 0 else 0][var.indice()]
677
+ value = states[1 if ifirst > 0 else 0][var.index()]
680
678
  else:
681
679
  value = bound[1 if ifirst > 0 else 0][var.qname()]
682
680
  var = var.qname()
@@ -909,8 +907,8 @@ class FiberTissueSimulation(myokit.CModule):
909
907
  self._ncellsf[1],
910
908
  self._ncellst[0],
911
909
  self._ncellst[1],
912
- self._vmf.indice(),
913
- self._vmt.indice(),
910
+ self._vmf.index(),
911
+ self._vmt.index(),
914
912
  self._gf[0],
915
913
  self._gf[1],
916
914
  self._gt[0],
myokit/_sim/jacobian.cpp CHANGED
@@ -70,12 +70,12 @@ typedef FirstDifferential Diff;
70
70
  <?
71
71
  print('// Aliases of state variable derivatives')
72
72
  for var in model.states():
73
- print('#define ' + v(var.lhs()) + ' deriv[' + str(var.indice()) + ']')
73
+ print('#define ' + v(var.lhs()) + ' deriv[' + str(var.index()) + ']')
74
74
  print('')
75
75
 
76
76
  print('// Aliases of state variable values')
77
77
  for var in model.states():
78
- print('#define ' + v(var) + ' state[' + str(var.indice()) + ']')
78
+ print('#define ' + v(var) + ' state[' + str(var.index()) + ']')
79
79
  print('')
80
80
 
81
81
  print('// Aliases of input variables')
myokit/_sim/jacobian.py CHANGED
@@ -4,14 +4,13 @@
4
4
  # This file is part of Myokit.
5
5
  # See http://myokit.org for copyright, sharing, and licensing details.
6
6
  #
7
- from __future__ import absolute_import, division
8
- from __future__ import print_function, unicode_literals
9
-
10
7
  import os
11
- import myokit
12
- import numpy as np
13
8
  import platform
14
9
 
10
+ import numpy as np
11
+
12
+ import myokit
13
+
15
14
  # Location of C source file
16
15
  SOURCE_FILE = 'jacobian.cpp'
17
16
 
@@ -45,7 +44,7 @@ class JacobianTracer(myokit.CppModule):
45
44
  _index = 0 # Unique id
46
45
 
47
46
  def __init__(self, model):
48
- super(JacobianTracer, self).__init__()
47
+ super().__init__()
49
48
 
50
49
  # Require a valid model
51
50
  model.validate()
@@ -216,13 +215,17 @@ class JacobianCalculator(myokit.CppModule):
216
215
  _index = 0 # Unique id
217
216
 
218
217
  def __init__(self, model):
219
- super(JacobianCalculator, self).__init__()
218
+ super().__init__()
220
219
  # Require a valid model
221
220
  model.validate()
222
221
 
223
222
  # Clone model
224
223
  self._model = model.clone()
225
224
 
225
+ # Store the initial values (won't be able to access once time binding
226
+ # is removed).
227
+ self._state = self._model.initial_values(as_floats=True)
228
+
226
229
  # Unbind all inputs
227
230
  for label, var in self._model.bindings():
228
231
  var.set_binding(None)
@@ -310,7 +313,7 @@ class JacobianCalculator(myokit.CppModule):
310
313
 
311
314
  # Get initial state
312
315
  if x is None:
313
- x = self._model.state()
316
+ x = self._state
314
317
  x = np.array(x)
315
318
 
316
319
  # Calculate derivatives & jacobian